[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [xmlblaster] More parsing issues

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
    at org.xmlBlaster.engine.xml2java.XmlKeyDom.parseKeyOid(XmlKeyDom.java:1
    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,

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.

John Horner

Open Roads Consulting
(757) 546-3401

Marcel Ruff
Phone: +49 7551 309371