Hi John,
John Horner wrote:
This message is (roughly speaking) a follow up to the previous message entitled
"Subscription Invocation Exception".
In addition to the problem described in that message I have also seen another
(possibly) similar problem. I have a unit test which creates 100 threads which
all try to make a subscription using the same xpath. In some cases (but not
always) one or more of the subscriptions fails with the following error:
java.lang.NoSuchMethodException: javax.xml.xpath.XPath.evaluate()
at java.lang.Class.getMethod(Class.java:1581)
at org.xmlBlaster.util.XmlNotPortable.getNodeSetFromXPath(XmlNotPortable
.java:137)
at org.xmlBlaster.engine.xml2java.XmlKeyDom.parseKeyOid(XmlKeyDom.java:1
25)
at org.xmlBlaster.engine.RequestBroker.queryMatchingKeys(RequestBroker.j
The intermittent nature of this problem (as well as the previously described
one) suggests to me that we are looking at a synchronization issue.
I have two synchronization concerns when looking at the code. The following
snip is from org.xmlBlaster.util.XmlNotPortable
public static Enumeration getNodeSetFromXPath(String expression,
org.w3c.dom.Document
document) throws XmlBlasterException {
try {
if (getJvmXmlVersionToUse() >= 15) {
if (method_newXPath == null) {
synchronized(XmlNotPortable.class) {
if (method_newXPath == null) {
... create xpath factory and objects ...
}
}
}
Object xpath =
method_newXPath.invoke(instance_XPathFactory, new Object[0]);
Object[] params =
new Object[] { expression, document, field_NODESET };
java.lang.reflect.Method method_evaluate =
clazz_XPath.getMethod("evaluate", paramCls_StringDocument);
final org.w3c.dom.NodeList nodes = (org.w3c.dom.NodeList)
method_evaluate.invoke(xpath, params);
The issues are:
1. The null check (method_newXPath == null) is outside the synchronization
block. Thread A and thread B could both pass through the null check at the
same time. Thread A will create the xpath objects while B waits. Then thread
B will go through and recreate xpath objects while A is using them.
if (method_newXPath == null) {
synchronized(XmlNotPortable.class) {
if (method_newXPath == null) {
method_newXPath creation is protected by the sync
and inside this with another null check (double-checked locking idiom).
This could theoretically fail as we have not set
method_newXPath to be "volatile".
2. XPathFactory is, in general, not thread-safe (see
http://java.sun.com/javase/6/docs/api/javax/xml/xpath/XPathFactory.html), and a
method on that object is invoked outside the synchro block.
Yes this is a bug.
We have fixed it and commited it to svn.
Thanks for reporting,
Marcel
I made a local change to wrap the synchro block around the null check and the
invocations following the original synchro. Once I did that I was unable to
reproduce the problem I described above.
I'd appreciate it if the xmlBlaster gurus could comment on the proposed change.
I'm happy to push the change up, but I'd like to get a little feedback first
if I can.
Thanks,
John Horner
Open Roads Consulting
(757) 546-3401
www.openroadsconsulting.com
--
Marcel Ruff
http://www.xmlBlaster.org
http://watchee.net
Phone: +49 7551 309371