Marcel Ruff
Thu, 03 Jan 2008 14:08:21 -0800
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