Skip to Content.
Sympa Menu

xom-interest - [XOM-interest] Re: XSLTTransform.setNodeFactory() thread safety

xom-interest AT lists.ibiblio.org

Subject: XOM API for Processing XML with Java

List archive

Chronological Thread  
  • From: Wolfgang Hoschek <whoschek AT lbl.gov>
  • To: xom-interest AT lists.ibiblio.org
  • Subject: [XOM-interest] Re: XSLTTransform.setNodeFactory() thread safety
  • Date: Fri, 10 Sep 2004 16:03:23 -0700

Since there has been zero feedback on this issue, here is a different perspective highlighting the very same problem:

A XSLTransform object conceptually should represent a compiled, inherently thread-safe stylesheet (just like a TRAX Templates object does). To apply the same XSL to N documents and get N outputs, one runs each document through the stylesheet, for each document using a NodeFactory that builds up the XML tree as desired.

Conceptually, the internal state of a XSLTransform should be a stylesheet, rather than a stylesheet + NodeFactory. Why? While the stylesheet is constant (i.e. immutable) across all invocations of a XSLTransform.transform(...), the (document,nodefactory) pair is *not* constant, in general. The pair may vary on each invocation. Further, when calling a NodeFactory, a XSLTransform must assume the worst case: a node factory that is stateful and mutable (most advanced node factories are like that).

Since currently XOM does not guarantee an immutable XSLTransform across varying (document,nodefactory) pairs,
multi-threaded apps face subtle synchronization race conditions, counter-intuitive workarounds and/or wild inefficiencies (e.g. holding a lock for the entire duration of a transform) that are a direct result of this XOM design deficiency. These problems are not theoretic, but very real and immediate for any XOM app running within a servlet engine, J2EE container - essentially all server-side development.

As already reported previously, the fix is to have a

XSLTransform.transform(Document, NodeFactory)

method, an analogous sister method for Nodes, and to remove NodeFactory as internal state in XSLTransform.
This would result in a XSLTransform class that is conceptually straightforward, clean, easy to understand, effective and immune to problems related to threading & reuse.

Sooner or later more people will run into this problem. Fixing the API before 1.0 means less trouble down the road.

Wolfgang.

On Sep 7, 2004, at 1:58 PM, Wolfgang Hoschek wrote:

There seems to be a potential problem wrt. thread safety of XSLTTransform.setNodeFactory().
Assume an app drives XSLTransform.transform concurrently from multiple threads and it uses a custom node factory that is stateful (keeps track of current state for non-trivial streaming transforms).
Without additional synchronization measures the node factory would run into race conditions.

To make it thread safe the most reasonable approach is *not* to have the node factory be thread safe (leads to heavy and long lived lock contention) but to have one independent node factory object per thread.
In this case synchronizing on setNodeFactory before each transform() is cumbersome, non-intuitive and error-prone.
If there were a method XSLTransform.transform(Document, NodeFactory) one could provide a new node factory on each invocation and gain thread safety in a straightforward manner.

Another option would be to have an XSLTransform object per thread. That would work around it, but seems counter-intuitive since that would somewhat defeat the purpose of the Templates object. The whole idea of a Templates object is that it is implicitly thread safe and can efficiently be reused many times via the cheap templates.newTransformer() [e.g. XSLTC].

Another option would be to have XSLTransform have a method that creates a NodeFactory on each transform(). Seems too complicated. Yet another option would be to have a NodeFactoryFactory class (creates a NodeFactory). Again seems too complicated for what it's worth.

Thoughts?






Archive powered by MHonArc 2.6.24.

Top of Page