You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by "Niall Pemberton (JIRA)" <ji...@apache.org> on 2007/01/05 05:50:27 UTC

[jira] Updated: (JXPATH-2) [jxpath] Using JXPath in multiple threads

     [ https://issues.apache.org/jira/browse/JXPATH-2?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Niall Pemberton updated JXPATH-2:
---------------------------------

    Fix Version/s: 1.3

> [jxpath] Using JXPath in multiple threads
> -----------------------------------------
>
>                 Key: JXPATH-2
>                 URL: https://issues.apache.org/jira/browse/JXPATH-2
>             Project: Commons JXPath
>          Issue Type: Bug
>         Environment: Operating System: All
> Platform: All
>            Reporter: Robert Sax
>             Fix For: 1.3
>
>
> 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

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org