I have been looking at how to simplify some of my rules which are manually written in DRL, becoming difficult to maintain.
Searching through google resulted in "decision tables is the best way to go forawad".
But unfortunately our facts are very complex, So at moment drools spreadsheetconverter, can not handle so much complexity on facts,
So the first question is how do developers normally deal with handling very complex facts in the drools knowledge base?
For example We have facts like
Person->List<Cars>->List<Insurances>->Each insurance Has List<History>
Now i have to write a rule say Person Has bad history for his Insurance claim. Then i find very diffcult to put it in speadsheet, where as its easier to manually write this rule on the drl file.
Thanks for the help. Any help on the above example would be very good too .
For complex rules like this, we use Drools Templates. You write a rule template with parameter expansions for fields to populate and you have much more flexibility in where the actual values come from to populate the skeleton rule.
This capability is built into Drools Guvnor, but writing the complex rule templates through the GUI is somewhat tedious. I have also written standalone Java to populate template drl files from lists of values pulled from properties files, and recently developed a SmartGWT web app that allows the user to populate rule values and generate DRL.
Edit: Adding sample program. DroolsTemplateBuilder creates a list of TestType objects, which have fields that map to the template keys in Test.drl. The generated DRL is printed and also compiled to a pkg which is written out to a file called Test.pkg.
Libraries: antlr-3.3.jar, antlr-runtime-3.3.jar, drools-compiler-5.2.0.Final.jar, drools-core-5.2.0.Final.jar, drools-templates-5.2.0.Final.jar, ecj-4.2.jar, knowledge-api-5.2.0.Final.jar, mvel2-2.1.0.drools.jar (these may not all be necessary).
Note: This example uses 5.2.0 libraries and some functionality may be different in newer releases. build.xml should make it clear how to structure your project.
DroolsTemplateBuilder.java:
package some.test.pkg;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.common.DroolsObjectOutputStream;
import org.drools.definitions.impl.KnowledgePackageImp;
import org.drools.io.ResourceFactory;
import org.drools.template.ObjectDataCompiler;
public class DroolsTemplateBuilder {
private String filePath;
private String drl;
public static void main(String[] args) {
DroolsTemplateBuilder test = new DroolsTemplateBuilder();
test.filePath = args[0] + File.separator + "Test.drl";
test.runTest();
}
public void runTest() {
buildPackage();
writeRulePackageToFile();
}
public void buildPackage() {
Collection<Object> templateList = new ArrayList<Object>();
templateList.add(new TestType(1, "John", "Manager"));
templateList.add(new TestType(2, "Peter", "CEO"));
templateList.add(new TestType(3, "Kate", "Engineer"));
try {
ObjectDataCompiler converter = new ObjectDataCompiler();
InputStream templateStream = new FileInputStream(filePath);
String myDrl = inputStreamToString(templateStream, 200);
// I use this ##### replacement instead of just a newline in the
// template
// because of windows/linux issues with newline and carriage return.
// Drools template
// builder, at least in 5.2.0, was very picky about the template
// structure, including
// where newlines are expected.
myDrl = myDrl.replaceAll("#####", "\n");
InputStream tempStream = new ByteArrayInputStream(myDrl.getBytes());
drl = converter.compile(templateList, tempStream);
System.out.println(drl);
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}
public void writeRulePackageToFile() {
try {
KnowledgeBuilder kBuilder = KnowledgeBuilderFactory
.newKnowledgeBuilder();
Reader rdr = new StringReader(drl);
kBuilder.add(ResourceFactory.newReaderResource(rdr),
ResourceType.DRL);
if (kBuilder.hasErrors()) {
System.out.println("Drools blew up on");
for (KnowledgeBuilderError err : kBuilder.getErrors()) {
System.out.println(err.getMessage());
}
} else {
String outFile = filePath.replaceFirst("\\.drl", ".pkg");
OutputStream os = new FileOutputStream(outFile);
ObjectOutputStream oos = new DroolsObjectOutputStream(os);
KnowledgePackageImp kPackage = (KnowledgePackageImp) kBuilder
.getKnowledgePackages().iterator().next();
oos.writeObject(kPackage);
oos.close();
}
} catch (Exception e) {
System.out.println("Exception " + e.getMessage());
}
}
public String inputStreamToString(final InputStream is, final int bufferSize) {
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try {
final Reader in = new InputStreamReader(is, "UTF-8");
try {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println("Something went wrong: " + ex.getMessage());
}
return out.toString();
}
}
Test.drl:
template header
id
name
title
#####
package some.test.pkg;
template "sampleTemplate"
rule "id filter_#{row.rowNumber}"
no-loop true
dialect "java"
when
$t : TestType(id=="#{id}")
then
System.out.println("Doing something special...");
end
end template
template "anotherSample"
rule "another rule_#{row.rowNumber}"
no-loop true
dialect "java"
when
$t : TestType((name=="#{name}") || (title=="#{title}"))
then
System.out.println("Doing something else...");
end
end template
TestType.java:
package some.test.pkg;
public class TestType {
private int id;
private String name;
private String title;
public TestType(int id, String name, String title) {
this.id = id;
this.name = name;
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
build.xml:
<project name="TemplateTest" basedir="." default="jar">
<property name="src.dir" value="src" />
<property name="build.dir" value="build" />
<property name="drl.dir" value="${basedir}/drl" />
<property name="classes.dir" value="${build.dir}/classes" />
<property name="jar.dir" value="${build.dir}/jar" />
<property name="lib.dir" value="${basedir}/lib" />
<path id="compile.classpath">
<fileset dir="${lib.dir}" includes="*.jar" />
</path>
<path id="run.classpath">
<fileset dir="${jar.dir}" includes="*.jar" />
<fileset dir="${lib.dir}" includes="*.jar" />
</path>
<target name="clean">
<delete dir="${classes.dir}" />
<delete dir="${jar.dir}" />
</target>
<target name="compile" depends="clean">
<mkdir dir="${classes.dir}" />
<mkdir dir="${jar.dir}" />
<javac includeantruntime="false" srcdir="${src.dir}" classpathref="compile.classpath" destdir="${classes.dir}" />
</target>
<target name="jar" depends="compile">
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
</jar>
</target>
<target name="run" depends="jar" description="run">
<java classpathref="run.classpath" classname="some.test.pkg.DroolsTemplateBuilder" fork="true">
<arg value="${drl.dir}" />
</java>
</target>
</project>
We also use Templates and our facts (and resulting rules) are quite complex. The values in the template table are used in the rules for method calls, setting rule "options," timer values, etc.
Templates help when the rule parameters lend themselves to a tabular format. If access control is of concern you may end up needing multiple templates with the same logic, just different values. (Easy to do in guvnor by just copying the 1st template).
Related
Here is my code
public class Environment {
public static String baseURL;
public static String setURL(String paramSet) {
/*
#BeforeSuite
#Parameters("env")
*/
if (paramSet.equalsIgnoreCase("Production")) {
baseURL = Constants.prodBase;
} else if (paramSet.equalsIgnoreCase("Staging")) {
baseURL = Constants.stagingBase;
}
return baseURL;
}
public static void getURL() {
RestAssured.baseURI = setURL("Production");
}
}
In the method getURL() i want to pass the parameter in the method setURL(myvariable) having value as Staging/Production from TestNG.xml file. I know i can pass it as parameters but this function getURL() will be called in each test and requirement is not to pass a parameter in every method for this.
Parameters({ "env-param" })
#BeforeSuite
public void prameterTestOne(String env) {
System.out.println("Test one suite param is: " + env);
}
XML file
<suite name="Parameter test Suite" verbose="1">
<!-- This parameter will be passed to every test in this suite -->
<parameter name="suite-param" value="Production / Staging" />
<test name="Parameter Test one">
<classes>
<class name="someClassName">
</class>
</classes>
</test>
I'm new to selenium, can anyone help me on how to run the same test case in 2 different URL which has the same functionality
Two ways you can do it.
1) Passing value from xml in testng file.
Test code you can refer.
public class ParameterTest
{
#Parameters({ "url" })
#Test
public void optionTest(String value) {
System.out.println("This is: " + value);
}
}
<suite name="Optional test Suite" verbose="1">
<test name="Optional Test one">
<parameter name="url" value="https://xy.cm" />
<classes>
<class name="test.parameter.OptionalTest" />
</classes>
</test>
<test name="Optional Test two">
<parameter name="url" value="https://abc.om" />
<classes>
<class name="test.parameter.OptionalTest" />
</classes>
</test>
</suite>
2) You can use data provider in testng to pass url as parameter in your test case.
public class SameClassDataProvider
{
#DataProvider(name = "url")
public Object[][] dataProviderMethod() {
return new Object[][] { { "https://yahoo.com" }, { "https://google.in" } };
}
#Test(dataProvider = "data-provider")
public void testMethod(String url) {
//write your test case
}
}
Hope this help you!
I am having this errors:
1- Multiple markers at this line - String cannot be resolved to a variable - Syntax error on token "food", delete
2- Multiple markers at this line
- Syntax error on token "detail", delete
this token
- String cannot be resolved to a variable
I marked these lines with ** in NewPortlet.java
. Below are my two related files
NewPortlet.java
package com.test;
import java.io.IOException;
import java.util.Date;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import com.liferay.counter.service.CounterLocalServiceUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.servlet.SessionMessages;
import com.liferay.portal.kernel.util.Constants;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class NewPortlet extends MVCPortlet {
public static String VIEW_JSP ="/html/new/view.jsp";
#Override
public void doView(RenderRequest renderRequest, RenderResponse renderResponse ) throws IOException, PortletException {
//renderRequest
super.doView(renderRequest, renderResponse);
}
public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws IOException, PortletException {
String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
try {
if (cmd.equals(Constants.ADD)){
String food = ParamUtil.getString(actionRequest, "food");
String detail = ParamUtil.getString(actionRequest, "detail");
long userId = CounterLocalServiceUtil.increment();
User user_= UserLocalServiceUtil.createUser(userId);
** user_.setFood(food);
** user_.setDetail(detail);
user_.setCreateDate(new Date());
UserLocalServiceUtil.updateUser(user_ , false);
SessionMessages.add(actionRequest,"food-added-succesfuly");
}
}catch (SystemException e) {
//TODO Auto-generated Catch block
e.printStackTrace();
}
super.processAction(actionRequest, actionResponse);
}
}
}
and my service builder
<entity name="Food" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="foodId" type="long" primary="true" />
<!-- Group instance -->
<column name="food" type="string" />
<column name="detail" type="string" />
<column name="createDate" type="new Date()" />
...
You are trying to add Food entity but you have used user entity instead.
User entity does not have any attribute/column as food or detail.
To add Food entity you have to use code as below.
long userId = CounterLocalServiceUtil.increment(Food.class);
Food foodEntry_=FoodLocalServiceUtil.createFood(userId);
foodEntry_.setFood(food);
foodEntry_.setDetail(detail);
foodEntry_ .setCreateDate(new Date());
FoodLocalServiceUtil.updateUser(foodEntry_ , false);
SessionMessages.add(actionRequest,"food-added-succesfuly");
I am developing a restful WS and I want to give the option to the users to take data back from my WS in the form of XML or Json and also to be able to choose a callback function if they want Jsonp. This is what I have until now and the part with the Interceptors is based on CXF - JAX-RS : Data Bindings.
My Rest Service:
#GET
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Produces({ "application/x-javascript", MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getServers(#Context ServletContext context,
#Context Request request,
#QueryParam("format") String format,
#QueryParam("callback") String callback) {
some code where server object is created....
if(format.equals("json"){
if(callback!= null){
response = Response.status(Status.OK).type("application/x-javascript")
.entity(server).build();
}else{
response = Response.status(Status.OK).type("application/json")
.entity(server).build();
}
} else {
response = Response.status(Status.OK).type("application/xml")
.entity(server).build();
}
return response;
}
My Server object:
#XmlRootElement (name="Server")
public class Server implements Serializable {
private String name=null;
private String hardware = null;
public Server(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHardware() {
return hardware;
}
public void setHardware(String hardware) {
this.hardware = hardware;
}
}
My beans.xml in the WEB-INF:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<context:property-placeholder/>
<context:annotation-config/>
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"/>
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"/>
<jaxrs:server id="services" address="/">
<jaxrs:serviceBeans>
<bean class="com.ba.serversws_cxf.resources.MyResource" />
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpInInterceptor">
<property name="callbackParam" value="callback"/>
</bean>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPreStreamInterceptor">
<property name="mediaType" value="application/x+javascript"/>
</bean>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPostStreamInterceptor"/>
</jaxrs:outInterceptors>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
</beans>
The error that I get when I set the query parameter "callback" is:
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor writeResponseErrorMessage
WARNING: No message body writer has been found for response class Server.
It works fine for other other two cases.
I have searched to find a solution but still nothing.
Any ideas?
Thanks
Here is my class that #Overrides the wrtieTo() method of the org.apache.cxf.jaxrs.provider.json.JSONProvider;
First of all in my beans.xml file I have used the <jaxrs:extensionMappings> and I have declared a jsonp extention.
Here is the code
<jaxrs:server id="services" address="/">
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
<entry key="jsonp" value="application/javascript"/>
</jaxrs:extensionMappings>
</jaxrs:server>
And below is my code of the writeTo() method that I have #Override
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.cxf.jaxrs.provider.json.JSONProvider;
import org.apache.cxf.jaxrs.utils.HttpUtils;
#SuppressWarnings("rawtypes")
#Produces("application/javascript")
public class JsonpProvider extends JSONProvider {
#SuppressWarnings("unchecked")
#Override
public void writeTo(Object obj, Class cls, Type genericType,
Annotation[] anns, MediaType m, MultivaluedMap headers,
OutputStream os) throws IOException {
String requestURI = getContext().getHttpServletRequest()
.getRequestURI();
if (requestURI.contains(".jsonp")) {
String prefix = getContext().getHttpServletRequest().getParameter(
"_jsonp");
if (prefix != null && !prefix.isEmpty()) {
os.write(prefix.getBytes(HttpUtils.getSetEncoding(m, headers,
"UTF-8")));
} else {
os.write("callback".getBytes(HttpUtils.getSetEncoding(m,
headers, "UTF-8")));
}
os.write('(');
super.writeTo(obj, cls, genericType, anns, m, headers, os);
os.write(')');
} else {
super.writeTo(obj, cls, genericType, anns, m, headers, os);
}
}
}
So what I am doing in the code above is I am checking if the .jsonp extension has been given to the URL. If yes then I know that I have to return the jsopn with a callback function. The last thing is to set the name of the callback function. If the user has set the _jsonp query parameter to the URL then the value of this parameter will be the name of the callback function. If the _jsonp pquery parameter is null then I put a defult name callback.
And off course in the beans.xml file as a json provider you put the JsonpProvider above:
<jaxrs:providers>
<bean class="org.apache.cxf.jaxrs.ext.search.SearchContextProvider"/>
<bean class="com.ba.serversws_cxf.utils.JsonpProvider">
<property name="ignoreNamespaces" value="true" />
<property name="dropRootElement" value="false" />
<property name="supportUnwrapped" value="true" />
</bean>
</jaxrs:providers>
Hope that helps #bhuvan !
I'm using GWT 2.1 java.util.logging emulation to log client side messages. According to the doc, two Formatters are provided (TextFormatter and HTMLFormatter) which are appropriate to client side logging.
Can anyone provide an example on how to setup a formatter and attach it to a handler in GWT?
Thanks
See the GWT documentation for logging here. It really depends on where you want your logging to appear, but if you only care about logging in Dev mode then you only need the SystemLogHandler and the DevelopmentModeLogHandler. The ConsoleLogHandler and FirebugLogHandler are used for web mode logging to chrome, firebug and firebug lite. The PopupLogHandler and HasWidgetsLogHandler add the log messages to some sort of UI element. All of the above should be capable of being enabled/disabled in the .gwt.xml except the HasWidgetsLogHandler which requires an associated widget container. This should be possible by adding the following:
<inherits name="com.google.gwt.logging.Logging"/>
<set-property name="gwt.logging.logLevel" value="SEVERE"/> # To change the default logLevel
<set-property name="gwt.logging.enabled" value="FALSE"/> # To disable logging
<set-property name="gwt.logging.consoleHandler" value="DISABLED"/> # To disable a default Handler
<set-property name="gwt.logging.developmentModeHandler" value="DISABLED" />
<set-property name="gwt.logging.popupHandler" value="DISABLED" />
<set-property name="gwt.logging.systemHandler" value="DISABLED" />
<set-property name="gwt.logging.firebugHandler" value="DISABLED" />
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
etc...
Here is a simple example of adding a Log handler to the Root logger. The logger uses the HTMLLogFormatter and puts the message in a HTML widget.
HTML html = new HTML();
// add the html widget somewhere in your code.
Logger.getLogger("").addHandler(new Handler() {
{
// set the formatter, in this case HtmlLogFormatter
setFormatter(new HtmlLogFormatter(true));
setLevel(Level.ALL);
}
#Override
public void publish(LogRecord record) {
if (!isLoggable(record)) {
Formatter formatter = getFormatter();
String msg = formatter.format(record);
html.setHTML(msg);
}
}
});
Also have a look at HasWidgetsLogHandler, which basically does what the handler in the example above does.
Here are the two classes I ended up using:
import java.util.Date;
import java.util.logging.LogRecord;
import com.google.gwt.logging.impl.FormatterImpl;
public class LogFormatter extends FormatterImpl {
private static final StringBuilder sb = new StringBuilder();
#Override
public String format(LogRecord rec) {
synchronized (sb) {
sb.setLength(0);
sb.append(new Date(rec.getMillis()).toString());
sb.append(": ");
sb.append(rec.getMessage());
sb.append("\n");
return sb.toString();
}
}
}
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ALog {
/* IMPORTANT: User blank string (root logger) here or else it WILL NOT have the formatter being used */
private static final Logger logger = Logger.getLogger("");
static {
for (Handler handler : logger.getHandlers()) {
handler.setFormatter(new LogFormatter());
handler.setLevel(Level.ALL);
}
}
public static void log(String msg) {
logger.log(Level.INFO, msg);
}
public static void log(String msg, Throwable e) {
logger.log(Level.INFO, msg, e);
}
}