In this example I will perform the bussiness rules validation inside an advice class, but you can implement the same mechanism to perform that validation inside a JSF backing bean or in a spring bean.
Inside your application-context.xml file add your advice in the following way:
<bean id="validatorAspect"
class="com.foo.aspects.BackingBeanValidatorAdvice"
factory-method="aspectOf">
<property name="resources">
<list>
<value>/com/foo/business/rules.drl</value>
</list>
</property>
</bean>
I'm assuming you have basic knowledge of Drool, I will not get into syntax details here, there is a lot of documentation in Drool's site; instead I will just present a simple validation rule file rules.drl:
package com.foo.business
import com.foo.model.ModelBean;
import com.foo.aspects.Error;
query "Error" ()
error : Error()
end
rule "Rule 1"
when
ModelBean( id == 32 && internalId not matches "(J|P|R) ([0-9]){6}")
then
Error err = new Error();
err.setSummary("Error in Model Bean. ");
err.setDetail("Internal Id not matches format: (J, P o R) followed by whitespace and 6 digits");
insert(err);
end
Error is just a simple Pojo containing two properties (summary and detail).
Then, you must fire the validation inside the advice class:
public aspect BackingBeanValidatorAdvice {
private KnowledgeBase kbase;
private StatefulKnowledgeSession ksession;
private String[] resources;
pointcut doSaveChanges() : execution(* com.foo.beans.BackingBean.saveChanges(..));
void around() : doSaveChanges() {
FacesContext context = FacesContext.getCurrentInstance();
ModelBean mbean = context.getApplication().evaluateExpressionGet(context, "#{bBean.selected}", ModelBean.class);
this.init();
this.getKsession().insert(mbean);
this.getKsession().fireAllRules();
QueryResults results = this.getKsession().getQueryResults("Error");
if (results.size() > 0) {
for (QueryResultsRow row : results) {
Error err = (Error) row.get("error");
context.addMessage("error", new FacesMessage(FacesMessage.SEVERITY_ERROR, err
.getSummary(), err.getDetail()));
}
}
proceed();
}
public void init() {
if (this.getKbase() == null) {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
for (int i = 0; i < this.getResources().length; i++) {
String rule = this.getResources()[i];
kbuilder.add(ResourceFactory.newInputStreamResource(this.getClass().getResourceAsStream(rule)),
ResourceType.DRL);
}
if (kbuilder.hasErrors()) {
System.out.println(kbuilder.getErrors());
return;
}
Collection < KnowledgePackage > kpkgs = kbuilder.getKnowledgePackages();
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kpkgs);
this.setKbase(kbase);
}
this.setKsession(this.getKbase().newStatefulKnowledgeSession());
}
public StatefulKnowledgeSession getKsession() {
return ksession;
}
public void setKsession(StatefulKnowledgeSession ksessionToSet) {
this.ksession = ksessionToSet;
}
public String[] getResources() {
return resources;
}
public void setResources(String[] resourcesToSet) {
this.resources = resourcesToSet;
}
public KnowledgeBase getKbase() {
return kbase;
}
public void setKbase(KnowledgeBase kbase) {
this.kbase = kbase;
}
}
That's it. In case the validation fails, a FacesMessage is added to the FacesContext and JSF is responsible for handling and showing the error in a jsf page, eg: <h:messages .../>