Sunday, June 3, 2012

Daogen a Generator for JPA Dao Implementations

Recently I created a small library to generate Java JPA Dao's from Dao interface type annotated with query string. There are no runtime dependencies other the javax.persistence. Compile-time dependencies are freemarker and jalopy.
One of the drawbacks of using Named Queries in JPA is that you have to attach the query definitions either as annotation to an Entity class or put them manually in separate orm mapping files (XML). Daogen lets you attach query string as annotation to a method in your Dao interface type like this:
@DaoTypepublic interface CustomerDao {        
   @JpaNamedQuery(query = "select c from Customer c where name = :name")    
   List<Customer> findByName(String name);    

   @JpaNamedQuery(query = "select c from Customer c where name = :name
        and c.creationDate < :date", throwException = false)    
   Customer findByUniqueNameAndBeforeDate(String name, @JpaTemporal(TemporalType.DATE)Date date);    
   
   @JpaNamedQuery(query = "select c from Customer c where name = :name", throwException = true)    
   Customer findByUniqueNameMandatory(String name);    
   
   @JpaNamedQuery(query = "select o from Order o where o.customer.id = :id")    
   List<Order> findOrdersByCustomerId(Long id);    
}
Daogen will create Dao implementations for all Dao interface types, in this case CustomerDaoImpl. Method parameters are matched against query parameter names. If you don't want named queries you can use dynamic queries by using @JpaQuery instead of @JpaNamedQuery. Furthermore it generates one queries-orm.xml file for all named queries.
@Generated(value="Generated by nl.koelec.daogen.gen.DaoProcessor", date = "Mon May 28 21:43:32 CEST 2012")
public class CustomerDaoImpl extends AbstractDao implements CustomerDao {    
   private final EntityManager entityManager;    

   public CustomerDaoImpl(EntityManager entityManager) {        
       this.entityManager = entityManager;    
   }    

   @Override        
   protected EntityManager getEntitymanager() {
       return entityManager;        
   }
    
   @Override        
   public List findByName(String name) {
      Query query = getEntitymanager().createNamedQuery("CustomerDao.findByName"); 
      setParam("name", name, null, query);            
      return query.getResultList();        
   }
   ...
}

queries-orm.xml:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" 
    http://java.sun.com/xml/ns/persistence/orm 
    http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"version="1.0">
<!-- @Generated(value="Generated by nl.koelec.daogen.gen.DaoProcessor",
date = "Mon May 28 21:43:32 CEST 2012") -->
<named-query name="CustomerDao.findByName"> <query><![CDATA[ select c from Customer c where name = :name ]]></query></named-query>
<named-query name="CustomerDao.findByUniqueNameAndBeforeDate"> <query><![CDATA[ select c from Customer c where name = :name and c.creationDate < :date ]]></query></named-query>
...
</entity-mappings>

The queries-orm file is referenced from persistence.xml like so:
<persistence-unit name="testPU" transaction-type="RESOURCE_LOCAL">
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <mapping-file>queries-orm.xml</mapping-file>
   ...

GITHUB

The code is in github and can be build with gradle
There are three gradle projects: daogen-core, dao-gen-processor and daogen-sample, each containing just a couple of java class files and some freemarker template files (part of daogen-processor).At runtime you will only need daogen-core. The daogen-processor jar contains the AnnotationProcessor used to generate the files at compile time.
You can use the prebuild jar files from the dist folder right away. Or you can build the projects yourself and go from there. The gradlew.bat file in the base folder lets you build daogen from source, whithout installing anything in advance with the following invocation: gradlew.bat build
After this you can take a look at the generated code and the test code in daogen-sample.

Using daogen in your own project.

Maven

put this plugin config in your pom file.
<build>   
   <plugins>      
      <plugin>         
         <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
              <version>2.3.2</version>              
              <configuration>                 
                 <source>1.6</source>                 
                 <target>1.6</target>                 
                 <generatedSourcesDirectory>generated-sources/src/main/java</generatedSourcesDirectory><annotationProcessors>
              <annotationProcessor>nl.koelec.daogen.gen.DaoProcessor</annotationProcessor>  
              </annotationProcessors>              
        </configuration>      
      </plugin>   
   </plugins>
</build>
Of course you also need the daogen-core and daogen-processor.jar as dependencies in your pom file.

Gradle

Look at gradle.build file in daogen-sample project.

Configuration

If you want you can override the used freemarker templates to change or add behaviour.Without supplying options to the DaoProcessor it will use the default templates packaged with the daogen-processor jar file.The following DaoProcessor options are supported:
  • templatedir folder where to look for override templates
  • ormtemplate queries orm template file name
  • daotemplate dao implementation template file name
  • daofactorytemplate dao factory implementation template file name
  • idaofactorytemplate dao factory interface template file name

Note

Don't forget to mark your Dao interface type with @DaoType at the class level.

Filter expressions in Rest urls leveraging QueryDsl Part 2

In my previous post I showed how to use QueryDsl-like BooleanExpressions as value of a Url query-parameter, as in this example:
http://www.myprettyproducts.com/product?filter="type.eq(3).and(prize.lt(500))"
The proposed solution leveraged both MVEL and QueryDsl to convert the filter expression at runtime to an executable QueryDsl expression.
As indicated in my post this approach introduced a security vulnerability as we open up our application to code injection via the filter expression. The filter expression is just a string which is interpreted by MVEL as Java code.
The way I defeated this is to restrict the expression string before it is given to MVEL. It is restricted to only accept terms and constructions that lead to a valid QueryDsl Predicate and nothing more. For this purpose I wrote a custom dynamic Parser using Parboild. Parboild is a socalled PEG (Parsing expression grammar) parser.
This is the grammar I came up with to parse the expressions:
FilterExpression : Expression
Expression       : MethodInvocation ['.'MethodInvocation]+
MethodInvocation : Method ArgumentList
Method           : Path
Path             : PathElement ['.'PathElement]+
PathElement      : 
ArgumentList     : '(' Argument? ['.'Argument]+ ')'
Argument         : Literal / Expression / Path / Array
Literal          : FloatLiteral / IntegerLiteral / CharLiteral
                    / StringLiteral / StringLiteral2 / 'true' / 'false' / 'null'
Array            : '[' (Literal / [','Literal]+) / (Expression / [','Expression]+)  ']'
The rule definition of the literal values is copied from an example for parsing of Java source code from the Parboiled website.
public class FilterExpressionParser extends BaseParser<Object> {
    private String[] allowedPathElements;

    public FilterExpressionParser(Collection<String> allowedPathElements) {
        this.allowedPathElements = (String[])allowedPathElements.toArray(new String[0]);
        Arrays.sort(this.allowedPathElements, new Comparator<String>() {
            @Override
            public int compare(java.lang.String o1, java.lang.String o2) {
                return o2.compareTo(o1);
            }
        });
    }

    Rule FilterExpression() {
        return Sequence(Expression(), EOI);
    }

    Rule Expression() {
        return Sequence(MethodInvocation(), ZeroOrMore(".", MethodInvocation()));
    }

    Rule MethodInvocation() {
        return Sequence(Method(), ArgumentList());
    }

    Rule ArgumentList() {
        return Sequence("(", Optional(Argument(), ZeroOrMore(",", Argument())), ")");
    }

    Rule Argument() {
        return FirstOf(Literal(), Expression(), Path(), Array());
    }

    Rule Array() {
        return Sequence("[",
                FirstOf(Sequence(Literal(), ZeroOrMore(",", Literal())), 
                Sequence(Expression(), ZeroOrMore(",", Expression()))),
                "]");
    }

    Rule Method() {
        return Path();
    }

    Rule Path() {
        return Sequence(FirstOf(allowedPathElements), ZeroOrMore(".", FirstOf(allowedPathElements)));
    }

    @MemoMismatches
    Rule LetterOrDigit() {
        // switch to this "reduced" character space version for a ~10% parser performance speedup
        return FirstOf(CharRange('a', 'z'), CharRange('A', 'Z'), CharRange('0', '9'), '_', '$');
        // return FirstOf(Sequence('\\', UnicodeEscape()), new JavaLetterOrDigitMatcher());
    }

    Rule Literal() {
        return FirstOf(Sequence(Optional("-"), FloatLiteral()), Sequence(Optional("-"),
                IntegerLiteral()), CharLiteral(),
                StringLiteral(), StringLiteral2(), Sequence("true", TestNot(LetterOrDigit())),
                Sequence("false", TestNot(LetterOrDigit())), Sequence("null", TestNot(LetterOrDigit()))

        );
    }

    @SuppressSubnodes
    Rule IntegerLiteral() {
        return Sequence(DecimalNumeral(), Optional(AnyOf("lL")));
    }

    @SuppressSubnodes
    Rule DecimalNumeral() {
        return FirstOf('0', Sequence(CharRange('1', '9'), ZeroOrMore(Digit())));
    }

    Rule HexDigit() {
        return FirstOf(CharRange('a', 'f'), CharRange('A', 'F'), CharRange('0', '9'));
    }

    Rule FloatLiteral() {
        return DecimalFloat();
    }

    @SuppressSubnodes
    Rule DecimalFloat() {
        return FirstOf(Sequence(OneOrMore(Digit()), '.', ZeroOrMore(Digit()), 
                Optional(Exponent()), Optional(AnyOf("fFdD"))),
                Sequence('.', OneOrMore(Digit()), Optional(Exponent()), Optional(AnyOf("fFdD"))),
                Sequence(OneOrMore(Digit()), Exponent(), Optional(AnyOf("fFdD"))),
                Sequence(OneOrMore(Digit()), Optional(Exponent()), AnyOf("fFdD")));
    }

    Rule Exponent() {
        return Sequence(AnyOf("eE"), Optional(AnyOf("+-")), OneOrMore(Digit()));
    }

    Rule Digit() {
        return CharRange('0', '9');
    }

    Rule CharLiteral() {
        return Sequence('\'', FirstOf(Escape(), Sequence(TestNot(AnyOf("'\\")), ANY)).suppressSubnodes(), '\'');
    }

    Rule StringLiteral() {
        return Sequence('"', ZeroOrMore(FirstOf(Escape(), 
               Sequence(TestNot(AnyOf("\r\n\"\\")), ANY))).suppressSubnodes(), '"');
    }

    Rule StringLiteral2() {
        return Sequence('\'', ZeroOrMore(FirstOf(Escape(), 
               Sequence(TestNot(AnyOf("\r\n'\\")), ANY))).suppressSubnodes(), '\'');
    }

    Rule Escape() {
        return Sequence('\\', FirstOf(AnyOf("btnfr\"\'\\"), OctalEscape(), UnicodeEscape()));
    }

    Rule OctalEscape() {
        return FirstOf(Sequence(CharRange('0', '3'), CharRange('0', '7'), CharRange('0', '7')),
                Sequence(CharRange('0', '7'), CharRange('0', '7')), CharRange('0', '7'));
    }

    Rule UnicodeEscape() {
        return Sequence(OneOrMore('u'), HexDigit(), HexDigit(), HexDigit(), HexDigit());
    }
}
You use it like this:
    private final static List queryDslMethods = Arrays.asList("and", "or", "not", "eq", "ne", 
"in", "notIn", "after", "before", "between", "notBetween", "lt", "loe", "gt", "goe",
"equalsIgnoreCase", "like", "matches", "startsWith", "startsWithIgnoreCase"); public Predicate toPredicate() { // create set with all terms that are allowed to appear as 'methods' in a filter expression Set allowedMethods = new HashSet(); set.addAll(queryDslMethods); set.addAll(Arrays.asList("type", "prize", "creationDate")); set.add("_date"); set.add("valueOf"); // needed for ValueFactory calls, i.e. _date.valueOf(...) // create the Parboiled parser with our FilterExpressionParser class FilterExpressionParser parser = Parboiled.createParser(FilterExpressionParser.class, allowedMethods); ReportingParseRunner<Object> parseRunner = new ReportingParseRunner<Object>(parser.FilterExpression()); // run the parser and examine result ParsingResult<Object> parsingResult = parseRunner.run(expression); if (!parsingResult.matched) { throw new IllegalArgumentException("filter expression is invalid: " + expression); } return evalExpression(expression); } private Predicate evalExpression(String expression) // create a map with all Objects that need to be available in the MVEL context. Map<String, Object> vars = new HashMap<String, Object>(); QProduct qProduct = QProduct.product; vars.put("type", qProduct.type); vars.put("prize", qProduct.prize); vars.put("creationDate", qProduct.creationDate); vars.put("_date", new DateFactory()); return (Predicate)MVEL.eval(expression, vars); }
If you want to use an entity property in a filter expression which type is not a primitive type or String, but for instance a java.util.Date object, then you can use a object factory for this. A factory creates an object instance from a string representation.
With the following factory you can construct date objects as part of a filter expression:
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class DateFactory {

    public String getName(){
        return "_date";
    }

    public Date valueOf(String value) {
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-mm-dd");
        return formatter.parseDateTime(value).toDate();
    }
}
You can see in the example code above the _date and valueof strings are added to the allowedMethods set for parsing the expression. Furthermore a DateFactory instance is put to the vars map with the name _date, so it is available when evalutaion the expression by MVEL. You use a date in a filter expression like this:
http://www.myprettyproducts.com/product?filter="type.eq(3).and(creationDate.after(_date.valueof('2012-05-23')))"
Of course you will need to parameterize the above code to make it reusable for different use cases.

Friday, March 30, 2012

Filter expressions in Rest urls leveraging QueryDsl Part I

The other day I was looking for a way to create dynamic filter expressions for use in a Restful webservice url. Clients should be able to pass arbitrary filter expressions to filter the results of a GET operation on a collection resource, which values are retrieved from a database by JPA. This idea came to me while using QueryDsl to construct where clauses in a typesafe manner. It would be nice if we could use QueryDsl-like BooleanExpressions as value of a Url query-parameter, like so:
http://www.myprettyproducts.com/product?filter="type.eq(3).and(prize.lt(500))"
In QueryDsl you use the generated QueryType classes to construct a BooleanExpression object which you can use in the where clause of a select query like this:
QProduct qProduct = QProduct.product;
  JPQLQuery query = new JPAQuery(entityManager).from(qProduct)
  .where(qProduct.type.eq(3).and(qProduct.prize.lt(500));
  return  query.list(qProduct);
Now if I could use qProduct.type.eq(3).and(qProduct.prize.lt(500) in a url and convert this string expression to Java code we are done.
Hey, wait a minute are we opening up the system for code injection? Yes, but there is a solution to this I will cover later on.
So how do we convert the expression string to Java code at runtime? I use MVEL for this part. That's a powerful evaluation language for Java applications, which evaluates a script. Now how it works is that you setup a map of key value pairs for the variables that are expected in the expression string. For the example above this would be: "type", qProduct.type and "prize", qProduct.prize. Code example:
This following code will take any valid expression string using the type and prize attributes. The conditional operators are the ones allowed by the QueryDsl QueryType metadata objects and depend on the attributes Type.
Predicate toProductPredicate(String expressionFilter){
  Map<String, Object> vars = new HashMap<String, Object>();
  vars.put("type", qProduct.type);
  vars.put("prize", qProduct.prize);
  return (Predicate)MVEL.eval(expressionFilter, vars);
}

public Collection<product> findAllProducts(String filterExpression){
  QProduct qProduct = QProduct.product;
  JPQLQuery query = new JPAQuery(entityManager).from(qProduct)
            .where(toProductPredicate(expressionString));
  return query.list(qProduct);
}

How to go about the code injection vulnerability.
You want to restrict the expression to only include terms and constructions that lead to a valid QueryDsl Predicate and nothing more. For this purpose I wrote a custom dynamic Parser using Parboild. Parboild is a socalled PEG (Parsing expression grammar) parser. See all detail in the followup post: Filter expressions in Rest urls leveraging QueryDsl Part 2

Sunday, October 30, 2011

JPA @Lob lazy loading

Suppose you have an Entity with (amongst others) a Lob field. How can you make sure the lob field is lazily loaded when your query returns a list of entity instances and you're only interrested in the other columns?
The first thing that comes to mind is instructing JPA to lazy load the field like this:
@Basic(FetchType.Lazy)
@Lob
byte[] attachment;

The problem with this is that in order to work the persistence provider needs to support it. When using Hibernate as JPA provider you have to instrument the bytecode at compile time.

What are the alternatives?

  • Create a separate Entity class containing all fields except the lob field and use this for the collection query.
  • Use a query with a projection to only include the non-lob fields

Sunday, October 23, 2011

JPA join queries need foreign key relationship

I needed a SQL query which is a projection of fields from five tables and looks like this in native SQL: (I reduced the number of tables in the code below to 2 for clearity)
SELECT refpoint.refid,refpoint.x,result.y 
FROM refpoint
LEFT OUTER JOIN result on result.refid = refpoint.refid
WHERE refpoint.refid IN (?,?)
Using QueryDsl and JPA I wrote this equivalent query:
QRefpoint refpoint = QRefpoint.refpoint;
QResult result = QResult.result;
JPQLQuery query = new JPQLQuery(entityManager);
long count = query(refpoint)
.leftJoin(result)
.with(result.refid.eq(refpoint.refid)
.where(refpoint.refid in (1,2)).count();
Running this code gave me:
16:07:20.619 [main] DEBUG org.hibernate.hql.ast.ErrorCounter - Path expected for join! antlr.SemanticException: Path expected for join! at org.hibernate.hql.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:360) ~[hibernate-core-3.5.6-Final.jar:3.5.6-Final]
After much experimentation I found out that JPA (and Hibernate) do not support Joining without a mapped relationship. In this case the tables Refpoint and Result have a weak relationship based on refid and although a join in native sql is possible you cannot do this from JPA and/or Hibernate.
The solution I came up with was creating a Database View and corresponding JPA entity like this:
CREATE VIEW RefpointResult as 
SELECT refpoint.refid,refpoint.x,result.y 
FROM refpoint
LEFT OUTER JOIN result on result.refid = refpoint.refid
and in Java:
QRefpointResult refresult = QRefpointResult.refpointresult;
JPQLQuery query = new JPQLQuery(entityManager);
long count = query(refresult)
.where(refresult.refid in (1,2)).count();

Sunday, November 21, 2010

When refactoring does not help

Part of an messaging application I'm working on contains a complex piece of code. This part deals with deciding on basis of content and recipients who is to receive an incoming message.
for (BusRoute route: busRoutes){
  if (route.isMatching(report)){
    for(MessageFilter filter: messageFilters){
      if (filter instanceof DelayOnBusRouteMessageFilter){
        DelayOnBusRouteMessageFilter delayFilter = (DelayOnBusRouteMessageFilter)filter;
        if (delayFilter.getBusRoute().equals(route)){
          if (route.isApproachingRoutePoint(report, delayFilter)){
            if (delayFilter.getDelayApproachingThreshold() < threshold || threshold == 0){
              threshold = delayFilter.getDelayApproachingThreshold();
              deltaThreshold = delayFilter.getDeltaThreshold();
              ....
            else....
             ...
          else ...
What's wrong with this code? Being overly complicated it is difficult to test and maintain and without doubt it will probably contain multiple errors, i.e. it is very difficult to verify that this piece of code indeed implements the specified  requirements of what this part of the application is supposed to do. Trying to refactor it to bring down the cyclomatic complexity (McCabe index - counts separate execution paths) didn't help much. I was looking for other ways to improve code quality when I remembered using a rule engine to implement business rules for a proof of concept some years back. Rule engines are good when you can write declarative rules and want to externalize business rules or have a requirement that the rules should be dynamically modifiable at runtime. Working with a rule engine requires a different way of thinking compared to OO or even functional programming. Some understanding of the rule engine basics is necessary before we go on.


Rule engine basics
Most rule engines are based on the Rete algorithm, which is a matching algorithm in modern forward-chaining inferencing rules engines. Without going into details, in contrast to naïve implementations which loop over each rule and check for matching conditions, the Rete algorithm builds a network of nodes, where each node corresponds to a pattern occurring in the condition part of a rule. A rule is defined with a condition (when) part and a consequence (then) part:
rule "my very simple first rule"
 when
  Person(age > 30 && < 40 || hair == "black")
 then
   retract(p)
In the condition part you access field constraints of the facts present in rule engine's working memory, f.i. to match all persons between 30 and 40 year of age or with black hair. Then in the consequence part you put actions to execute when this rule's condition evaluates to true and this rule is executed, f.i. the selected person is retracted from the rule engine's working memory. The normal sequence of interactions with a rule engine is as follows:
  1. insert all facts
  2. fire all rules
  3. retrieve the results
Facts are represented by object instances, for the example above we would have a Person object with a int property age and a String property hair. In the first step we insert each fact into the working memory of the engine, which implicitly constructs the network of matching conditions. Next we let the rule engine fire all rules against the inserted facts. The engine will put all rules for which the conditions evaluate to true in a certain order on an agenda list and then removes and executes the first rule on the agenda, i.e. run the consequence (then) part of the rule. If this execution changes the working memory (retract fact(s) or insert of new fact(s)) then all rules are again evaluated and a new agenda results from this. The engine then proceeds with the execution of the first rule on the agenda again. This process repeats itself until the agenda is empty. Now the fire-all-rules step has finished and we proceed with retrieving the results, which can be the list of remaining facts or an arbitrary result object created or filled by a rule consequence. From the above you may have noticed that the order in which rules are put on the agenda makes a big difference. Therefore rule engines offer additional directives to group and prioritize rules as they appear on the agenda. Also they offer a large variation in how you may construct the condition part and the consequence part, you can use rule engine's native language or may extend this language with a self written dsl. It is very important that the getters of Fact objects or other data consulted in the conditional part of rules may not have side effects, because of how the Rete algorithm works. Remember, only change fact data in the consequence part and don't forget to trigger the rule engine to reconsider the conditions of the rules if that happens.


Setting up the environment
I set out to work to rewrite the code as a set of rules to be executed by the rule engine. Since I'm working on a Java project, I selected  Drools Expert, open source software from Jboss/Redhat for this task. For a .Net project you could use Microsoft BRE. The remainder of this part will focus on setting up the Eclipse IDE to write (and debug) the rules and supporting code to use the Drools rule engine for a Java application. First we install the Jboss Tools plugin in Eclipse. This plugin gives us several rule editors, a Drools perspective and the execution/debug facilities for Drools. Now we can create a new Drools project or convert an existing project to a Drools project. If you choose for a new project, you can have a sample Hello World drools files generated, which provide great starting point for playing around with the rule engine. The following files are being generated:
  • Sample.drl
  • DroolsTest.java
rule "Hello World"
 when
  m : Message( status == Message.HELLO, myMessage : message )
 then
  System.out.println( myMessage ); 
  m.setMessage( "Goodbye cruel world" );
  m.setStatus( Message.GOODBYE );
  update( m );
end

rule "GoodBye"
 when
  Message( status == Message.GOODBYE, myMessage : message )
 then
  System.out.println( myMessage );
end
The first rule matches any Message with status equal to HELLO. In the consequence the message property is printed, the status of the message is changed to GOODBYE and also the message is changed. Two things to notice here. The 'm :', which binds a new local variable called 'm' to the matched Message instance. And also the myMessage variable is bound to the message property of the Message instance. The auto created variables can be references in subsequent 'when conditions' or in the consequence part of the rule like in this example. The second thing to notice is the update(m) statement, which notifies the rule engine that the Message instance was modified. This means that the engine will clear the agenda and reevaluate all rules, which sounds like a big thing, but can be accomplished very efficiently by the engine because of the Rete algorithm.
public class DroolsTest {

  public static final void main(String[] args) {
    try {
      // load up the knowledge base
      KnowledgeBase kbase = readKnowledgeBase();
      StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
      KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
      // go !
      Message message = new Message();
      message.setText("Hello World");
      message.setStatus(Message.HELLO);
      ksession.insert(message);
      ksession.fireAllRules();
      logger.close();
    } catch (Throwable t) {
      t.printStackTrace();
    }
  }

  private static KnowledgeBase readKnowledgeBase() throws Exception {
    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
    kbuilder.add(ResourceFactory.newClassPathResource("Sample.drl"), ResourceType.DRL);
    KnowledgeBuilderErrors errors = kbuilder.getErrors();
    if (errors.size() > 0) {
      for (KnowledgeBuilderError error : errors) {
        System.err.println(error);
      }
      throw new IllegalArgumentException("Could not parse knowledge.");
    }
    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
    kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
    return kbase;
  }

  public static class Message {
    public static final int HELLO = 0;
    public static final int GOODBYE = 1;
    private String text;
    private int status;
    getters and setters ...
  }
}
The following picture shows the audit logging after execution of the program. The audit log is a tremendous help in understanding how rules are executed.
Audit logging (click to enlarge)
Posted by Picasa
The Message object is inserted, which results in the creation of an activation (rule is placed on the agenda). This line of logging is a result of the line ksession.insert(message) in main(). Next the program calls fireAllRules(). This will execute the first activation on the agenda, i.e. Rule Hello World. The activiation is executed (i.e. the consequence part of the rule is executed) which creates an activiation of the Goodbye rule. Then the Goodbye rule activation is executed which completes the rule engine, because there are no activiations on the agenda.

Conclusion
Now we have some understanding of how a rule engine works. I´ve managed to apply this technology to resolve our complexity problem in the messaging application. The resulting rule files are small and concise and easily maintainable because there is a clear relation to the functional requirements.
Dependency injection (Spring, CDI) gave us the ability to create applications with loosly coupled components. A rule engine can help us improving the internal logic of components on specific spots where complex if.. then constructions cause maintenance to be a helluvajob.

Tuesday, November 16, 2010

Using Selenium and Ajax on Richfaces

We use Selenium for functional testing of a Web Application based on Seam 2 and Richfaces. The test script typically invokes an action by pushing a button or clicking a link, which submits a form or issues an Ajax Request. Next you wait for the new Page to load or wait for an element to (dis)appear or a specific element value change. Then you assert the elements on the page to have the expected values.
Sometimes a Ajax request doesn't result in any change on the page or you don't want to include the expected page changes in the waiting code. On what condition do we wait before continuing. The easiest and also uggliest way is to insert a sleep. Problem is that we have to sleep long enough for the server to finish the ajax call. This is considered bad practice because now the test completion depends on  the hardware the test is executed and all tests will execute a considerable time longer than strictly necessary.
In our application we use the Richfaces a4j:status component (html is: _viewRoot:status.start) to show an indicator (shows text 'busy') on the page while the ajax request is being processed.  I created a waitForAjax method in our test base class which conditionally waits until the indicator is shown on the page and suqsequently waits until the indicator disappears again.
protected void waitForAjax() {
       waitForAnyText("_viewRoot:status.start", 5);
       waitForNoText("_viewRoot:status.start", 5);
}

protected void waitForAnyText(final String locator,int timeoutAsSeconds){
   waitFor(new WaitForCallback(){
     public boolean conditionMet(){
       return !selenium.getText(locator).equals("");
     }
   }, timeoutAsSeconds);
}

protected void waitForNoText(final String locator,int timeoutAsSeconds){
   waitFor(new WaitForCallback(){
     public boolean conditionMet(){
       return selenium.getText(locator).equals("");
     }
   }, timeoutAsSeconds);
}

protected void waitFor(WaitForCallback cb, int timeoutAsSeconds){
  for(int second=0;;second++) {
    if (second >= timeoutAsSeconds){
      fail("timeout");
    }
    if(cb.conditionMet()){
      break;
    }
    try {
      Thread.sleep(1000);
    }
    catch (InterruptedException e){}
  }
}
protected static interface WaitForCallback {
  boolean conditionMet();
}

The problem with this code is that if the server is really quick, the Ajax indicator is already gone when the script executes the waitForAnyText("_viewRoot:status.start") call, and the test will fail after the specified timeout. To fix this we need a non failing waitForAnyText().

protected void waitForAjax() {
       waitForAnyText("_viewRoot:status.start", 5, false);
       waitForNoText("_viewRoot:status.start", true);
}
protected void waitForAnyText(final String locator,int timeoutAsSeconds, boolean fail){
   waitFor(new WaitForCallback(){
     public boolean conditionMet(){
       return !selenium.getText(locator).equals("");
     }
   }, timeoutAsSeconds, fail);
}

protected void waitForNoText(final String locator,int timeoutAsSeconds, boolean fail){
   waitFor(new WaitForCallback(){
     public boolean conditionMet(){
       return selenium.getText(locator).equals("");
     }
   }, timeoutAsSeconds, fail);
}

protected void waitFor(WaitForCallback cb, int timeoutAsSeconds, boolean fail){
  for(int second=0;;second++) {
    if (second >= timeoutAsSeconds){
      if (fail) {fail("timeout");} else {break;}
    }
    if(cb.conditionMet()){
      break;
    }
    try {
      Thread.sleep(1000);
    }
    catch (InterruptedException e){}
  }
}
So, now after calling waitForAjax() from our test script we know for certain that the ajax call completed and we have waited only the minimum amount of time.