DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG� RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://issues.apache.org/bugzilla/show_bug.cgi?id=34552>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND� INSERTED IN THE BUG DATABASE.
http://issues.apache.org/bugzilla/show_bug.cgi?id=34552 Summary: Using JXPath in multiple threads Product: Commons Version: unspecified Platform: All OS/Version: All Status: NEW Severity: normal Priority: P2 Component: JXPath AssignedTo: [email protected] ReportedBy: [EMAIL PROTECTED] I was unable to determine if JXPath was intended to be used concurrently or not, but after using it in a server application that runs 100+ threads concurrently, I started getting errors (they were rare) that showed the following trace: java.lang.NullPointerException at org.apache.commons.jxpath.ri.model.beans.BeanPropertyPointer.getPropertyNames(BeanPropertyPointer.java:72) at org.apache.commons.jxpath.ri.model.beans.PropertyIterator.prepareForIndividualProperty(PropertyIterator.java:248) at org.apache.commons.jxpath.ri.model.beans.PropertyIterator.setPositionIndividualProperty(PropertyIterator.java:141) at org.apache.commons.jxpath.ri.model.beans.PropertyIterator.setPosition(PropertyIterator.java:127) at org.apache.commons.jxpath.ri.axes.ChildContext.setPosition(ChildContext.java:106) at org.apache.commons.jxpath.ri.axes.ChildContext.nextNode(ChildContext.java:89) at org.apache.commons.jxpath.ri.EvalContext.nextSet(EvalContext.java:322) at org.apache.commons.jxpath.ri.axes.UnionContext.setPosition(UnionContext.java:55) at org.apache.commons.jxpath.ri.axes.NodeSetContext.nextNode(NodeSetContext.java:64) at org.apache.commons.jxpath.ri.EvalContext.constructIterator(EvalContext.java:181) at org.apache.commons.jxpath.ri.EvalContext.hasNext(EvalContext.java:114) at com.paychex.hrs.ei.conversion.jaxb.InboundProcessor.process(InboundProcessor.java:136) The code calling has next looks like: Iterator oIter = m_oIdentifier.iteratePointers(oXCtx); >>> while (oIter.hasNext()) { The application has 100 worker threads, each processing the same message(converted to beans by JAXB), but different instances of it. This error occurs infrequently - happening only about once every 3 runs (each run processes 1000 messages). I performed the test on a P4/Windows box, but I believe that this is independent of os/system. I believe I have found some of the source code that may be causing this. It appears that bean info is stored in an internal cache (JXPathIntrospector) that all threads would end up using. For this to be thread safe, JXPathIntrospector needs to be thread safe (which it is even though synchronization is not used), and JXPathBasicBeanInfo needs to be thread safe (it is not). Basically what is happening is that inside of JXPathBasicBeanInfo, a couple of procedures build member variables on demand. However this demand based building is not thread safe and so a race condition exists between multiple threads that are both performing the on demand building. Specifically getPropertyDescriptors and getPropertyDescriptor modify propertyDescriptors and propertyNames in an unsafe manner. Either synchronization should be used or the assignment to the member variable should be performed last (resulting in duplicate effort but thread safety). Here are the pieces of code I am referring to: public PropertyDescriptor[] getPropertyDescriptors() { if (propertyDescriptors == null) { try { BeanInfo bi = null; if (clazz.isInterface()) { bi = Introspector.getBeanInfo(clazz); } else { bi = Introspector.getBeanInfo(clazz, Object.class); } PropertyDescriptor[] pds = bi.getPropertyDescriptors(); propertyDescriptors = new PropertyDescriptor[pds.length]; // At this point, the cache of property descriptors has been cleared possibly // conflicting with other threads System.arraycopy(pds, 0, propertyDescriptors, 0, pds.length); Arrays.sort(propertyDescriptors, new Comparator() { public int compare(Object left, Object right) { return ((PropertyDescriptor) left).getName().compareTo( ((PropertyDescriptor) right).getName()); } }); } ... public PropertyDescriptor getPropertyDescriptor(String propertyName) { if (propertyNames == null) { PropertyDescriptor[] pds = getPropertyDescriptors(); propertyNames = new String[pds.length]; // At this point the property names has been cleared possibly conflicting with // other threads for (int i = 0; i < pds.length; i++) { propertyNames[i] = pds[i].getName(); } } Thanks, Rob Sax -- Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug, or are watching the assignee. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
