Yes, this is a bit clumsy, though there are a few tricks that might help.
 
You don't actually have to supply a TraceListener at the level of the TransformerFactory (or Configuration): you can switch tracing on at that level using the COMPILE_WITH_TRACING switch (or config.setCompileWithTracing()), and then supply the actual TraceListener at the Transformer level. This is new in 8.8 if I remember right. It's not the ultimate answer, because you're still compiling everything with tracing enabled, but there's nowhere in the JAXP model of things to set options for an individual compilation. The .NET API provides an XsltCompiler object to fill this gap, and I hope one day to build this into the Java interface too. 
 
Thinking about your requirement more carefully, I'm not entirely convinced by the idea. Compiling with trace code enabled (even if not activated at execution time) is going to impose a significant performance penalty and will actually increase the amount of stack space consumed. This seems a heavy price to pay for what you're trying to achieve. Also, because of tail-call optimization, some runaway recursion might not actually consume stack anyway, because the infinite recursion is actually executed as an infinite loop. Wouldn't it be better to think about your test strategy and try to design these bugs out of your code?
 
Michael Kay
http://www.saxonica.com/


From: saxon-help-bounces@lists.sourceforge.net [mailto:saxon-help-bounces@lists.sourceforge.net] On Behalf Of Kirschner, Larry
Sent: 31 October 2006 20:52
To: Mailing list for SAXON XSLT queries
Subject: Re: [saxon] max-recursion-depth setting for saxontransformerfactory?

Thanks for getting back so quickly.
 
Using a TraceListener as you described seems like it would be a good solution. I've been trying to implement it, but I've run into some snags.
 
The only way to attach a TraceListener and have it invoked properly is to add it at the TransformerFactory level, using either javax.xml.transform.TransformerFactory::setAttribute(String name, Object val) or a saxon-specific equivalent. This means that the all Transformers created by any one TransformerFactory will share a single TraceListener. This is a problem if you reuse TransformerFactory objects in a multithreaded environment, which is something that we do.
 
Below is a list of ways I've considered to get around this problem, but they all either won't work or are heinous. Short of changing all of our code to create a new TransformerFactory instance for every transform, is there any other reasonably simple way to make this work?
 
=============================================================================================
1) Add a new instance of the TraceListener to each Transformer instance directly using net.sf.saxon.Controller::addTraceListener
=============================================================================================
 
This doesn't work because the TraceListener seems to need to be compiled into the Transformer. If you add a TraceListener to an already existing Transformer, it doesn't make the enter() and leave() callbacks.
 
========================================================================================================
2) Use context from the TraceListener callbacks to multiplex event callbacks to a TraceListener bound to the callback's transform.
========================================================================================================
 
This would be a good solution, but there's not enough context in the callbacks to implement it. The one place I see where the context does exist is in the TraceListener::enter() callback, which has an XPathContext parameter. I could keep a table of TransformStackSizeListener objects and use XPathContext::getController() as the key. The problem is that leave() doesn't pass a context parameter, so I'd have no way to lookup the right TransformStackSizeListener on leave callbacks.
 
=====================================
3) Store Transform context in a thread-local variable
=====================================
 
This would work for the most part, but it would break if the tranformers were used in an nio setting.
 
====================================================================================================================
4) Use a custom WrapperTransformerFactory that wraps the saxon TransformerFactory and, under the covers, clones itself for every call to newTransformer() and newTemplates(). Each cloned TranformerFactory would have it's own instance of the TraceListener.
====================================================================================================================
 
This would be kind of an ugly solution. If we went this route, I think the way to do it would be to create a new instance of net.sf.sax.TranformerFactoryImpl passing a cloned net.sf.saxon.Configuration to its constructor. Unfortunately, the Configuration class doesn't implement Cloneable, so I'd have to copy over all the Configuration properties manually. Also, I'd be assuming that all TransformerFactory configuration settings really are encapsulated in that Configuration object.
 
Anyway, I was hoping you might know a way to do this that's better than all of the above. Any suggestions are greatly appreciated. Thanks again for your help.
 
Larry
 


From: saxon-help-bounces@lists.sourceforge.net [mailto:saxon-help-bounces@lists.sourceforge.net] On Behalf Of Michael Kay
Sent: Monday, October 30, 2006 6:00 PM
To: 'Mailing list for SAXON XSLT queries'
Subject: Re: [saxon] max-recursion-depth setting for saxon transformerfactory?

No, there's no setting to enable recursion to be throttled in this way. You could experiment with doing it yourself from a TraceListener, by counting the number of templates/functions that have been entered and not exited.
 
Michael Kay
http://www.saxonica.com/


From: saxon-help-bounces@lists.sourceforge.net [mailto:saxon-help-bounces@lists.sourceforge.net] On Behalf Of Kirschner, Larry
Sent: 30 October 2006 22:03
To: saxon-help@lists.sourceforge.net
Subject: [saxon] max-recursion-depth setting for saxon transformer factory?


We recently had a problem where a badly written xsl transform combined with bad input data would cause infinite recursion on transforms.

When this would happen, it would chew up huge chunks of memory on our app server processes, but not throw any error that would give an indication that an xsl transform was the cause.

Is there any kind of setting that can be applied to the TransformerFactory like "max-recursion-depth"? I was looking around at the javadocs at net.sf.saxon.Configuration, but I didn't see any setting along those lines.

Thanks,
Larry