Hi Guys,
I want to discuss a problem I have found
when using the combination of knowledge
agent + classpathResources.
I will try to describe what am I doing
first to give you some context.
I'm deploying drools-camel-server in a
Tomcat 7 container. Inside the
WEB-INF/classes directory I have some DRL
files that I want to use.
My knowledge-services.xml file declares
the following kagent:
<drools:kagent id="kagent1"
kbase="kbase1" new-instance="false">
<drools:resources>
<drools:resource type="DRL"
source="classpath:simple.drl"/>
...
</drools:resources>
</drools:kagent>
When spring parses this configuration
file it creates a KnowledgeAgent instance
with a ChangeSet containing all the listed
resources.
The next step is to start
ResourceChangeNotifierService
and ResourceChangeScannerService.
So far so good.
The problem:
The problem I'm having is not directly
related to drools, but I think it is quite
easy to provide a solution for the people
that is in my same situation.
ClassPathResource is the class that
represents a resource defined as "classpath:"
This class has 2 important methods:
public long getLastModified(){
return this.classLoader.getResource(
this.path
).openConnection().getLastModified();
}
public InputStream getInputStream(){
return this.classLoader.getResourceAsStream(
this.path );
}
The first method is used
by ResourceChangeScannerService to check
whether the resource has changed or not. It
works fine. When the resource in the
filesystem changes, the scanner detects the
change without any problem.
The scanner ends up notifying the kagent
about the change, and the kagent passes the
Resource to an instance of
KnowledgeBuilder.
An here is when things fail.
The kbuilder uses the second method
of ClassPathResource (getInputStream()) to
get the content of the resource. In the case
of Tomcat (and probably some other
environments), it seems that the classloader
(Tomcat's classloader) is using a cache. So
the InputStream returned doesn't reflect the
current state of the resource.
Long story short: the agent is notified
about a change in the resource, but the
change is never applied to the kbase because
the kbuilder is unable to get it :P
Solutions:
The first solution is not to use
classpath resources :). You can use just url
resources like
http://
or
file:/.
But honestly, when you have your rules
inside your webapp, it is much
more comfortable and even manageable to
avoid the use of real paths.
What I was thinking about (I already have
a working prototype) is to create a new
Resource type for these cases. This resource
type will let you define your resources
present in your classpath as usually but it
will translate them to URL Resource
internally.
So, in the example above:
<drools:resource type="DRL" source="URLClasspath:simple.drl"/>
Opinions?