Project

Profile

Help

Altering a Saxon-EE User's Configuration Within Custom Extension Code After Transform Start

Added by Anthony Bufort 5 months ago

Hello Once Again,

I have had my head in the Saxon Javadocs, and I see several methods related to setting a whole configuration (e.g. Configuration.instantiateConfiguration), with some described as customization hooks (e.g. Transform.initializeConfiguration). However, I am not certain how I would employ those to do a "hot reconfig" of a running Saxon instance (one which I myself was not responsible for starting programmatically), as I cannot figure out how I would obtain the current Configuration in the first place which I would want to alter and then use. Nor am I sure that Saxon would recognize my changes immediately during the run of the current transform the way I intend. (I am presuming Transform.initializeConfiguration might work, but not certain. My uncertainties are due to: (1) the fact that I am doing this based on a transformation not initiated by me (so no config handle), (2) that I am planning to do it within, for example, my ExtensionElementFactory class itself as a one-time-only initialization of said config changes and "enactment," and (3) that the transform has already started).

In other words, after a user starts a transform involving my extension classes and functions (whether via oXygen or the command line or wherever), I want to grab the current configuration from the running transform, alter it to register/bind my functions and elements, and then have saxon immediately recognize the resulting configuration effect for the running transform. "Just-in-time", "mid-stream," or "hot" registration, if you will. But it mustn't run roughshod over any existing configuration (whether file-based or programmatic). It should respect what the user set and merely add registration of my functionality, immediately recognizing said functionality.

I feel as though I know how to get most of the way there, but where I lose hope is in grabbing the current configuration as a Configuration object. Transform.getConfiguration() would have been perfect, but I see it is protected. I also see that it is possible to subclass this class, which would allow me access. However I have no desire to implement a whole 'nother CLI, compelling the user to deviate from standard by having to use it, in order to do so. The whole point of this exercise is under-the-covers handling of configuration and ultimate ease-of-use. A third possibility would be getting the current config based on a context (via Configuration.getConfiguration ). But I have no context to do that with that I know how to get to.

(A follow-up objective, as stated in another of my recent threads, would be to only register those functions being used by the present transform. But I digress.)

So how can I get a handle on the running Transform to grab its current Configuration? I know how to alter it once I have it in order to register my functionality. Then what do I use to "enact" it for the current transform?

(Java code skeleton of what I want to do)

public class ElementFactory implements ExtensionElementFactory {
	private static boolean isInited = false;
	
	public Class<? extends StyleElement> getExtensionClass(String localname) {
		
		if (! isInited) {
			try {
				// Read user's configuration, add extension registrations/bindings, then 'activate' altered config immediately
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		// Conditionals returning various extension-element functionality (StyleElement) classes, or if none found...
		
		return null;
	}
}

-Tony


Replies (5)

Please register to reply

RE: Altering a Saxon-EE User's Configuration Within Custom Extension Code After Transform Start - Added by Michael Kay 5 months ago

In other words, after a user starts a transform involving my extension classes and functions (whether via oXygen or the command line or wherever), I want to grab the current configuration from the running transform, alter it to register/bind my functions and elements, and then have saxon immediately recognize the resulting configuration effect for the running transform. "

That sounds like a recipe for disaster. The Configuration in general is shared by many concurrent transformations (and other processes) and trying to change it on the fly is likely to cause havoc.

There are many options that are scoped to a single transformation and you should be looking at those.

A transformation runs in two phases: compilation followed by execution. If the transformation contains static function calls then these need to be known when the stylesheet is compiled. Once the transformation has started running, it's too late to change anything.

The function library used for a particular XSLT compilation is held in the StylesheetPackage object. We haven't made this particularly easy to extend. It's constructed by StylesheetPackage.createFunctionLibrary(), and the variable parts largely come from the Configuration. The method createFunctionLibrary() is called immediately before the actual compilation so there's no opportunity to modify the function library in between.

Sorry, I don't see an obvious way forward on this. It's a scenario that we didn't envisage.

RE: Altering a Saxon-EE User's Configuration Within Custom Extension Code After Transform Start - Added by Anthony Bufort 5 months ago

Ok Mike, once again thanks for your reply. I can accept that altering the Configuration is not the way to go given all you've said re the implications.

Regardless, I will have a closer look at StylesheetPackage.createFunctionLibrary() to learn more, even if that won't be the route to success here.

I'll just have to weigh my options going forward and see what I land on.

When you say:

There are many options that are scoped to a single transformation and you should be looking at those.

... I want to, but how can I obtain the running Transformation that say an oXygen user has run of an XSLT (obtain it from within my function packages, that is)? I don't see how that's possible. If the user were running a Java program I wrote which itself sets up the Transformation object, then of course I have that already. But that isn't the case.

(You can see that I'm still learning these Saxon intricacies, and there are definitely gaps in my comprehension/knowledge I am trying to fill via these inquiries and my documentation readings and research. I have many years of XML-tech experience, including writing some extensions for older versions of Saxon, but now I am going "whole hog," so to speak.) :)

-Tony

RE: Altering a Saxon-EE User's Configuration Within Custom Extension Code After Transform Start - Added by Michael Kay 5 months ago

how can I obtain the running Transformation

You seem to be asking for some magic here whereby Saxon somehow knows who "you" are and calls your code without the actual program running the stylesheet asking it to do so. That seems a bit of a tall order; though we achieved something a bit similar with the -init configuration hook.

One approach might be to write your own implementation of the JAXP TransformerFactory (perhaps subclassing the Saxon version), and have the user nominate that as their transformation engine in Oxygen. That would give you an opportunity to inject your code at the point where the stylesheet is compiled.

RE: Altering a Saxon-EE User's Configuration Within Custom Extension Code After Transform Start - Added by Anthony Bufort 5 months ago

One approach might be to write your own implementation of the JAXP TransformerFactory (perhaps subclassing the Saxon version), and have the user nominate that as their transformation engine in Oxygen. That would give you an opportunity to inject your code at the point where the stylesheet is compiled.

This does seem like a fascinating and very promising way to go. It also would easily allow me to handle my secondary objective, which is to examine the XSL the user is transforming and only register those parts of my functionality which are actually required.

You seem to be asking for some magic here whereby Saxon somehow knows who "you" are and calls your code without the actual program running the stylesheet asking it to do so. That seems a bit of a tall order; though we achieved something a bit similar with the -init configuration hook.

Yes, after further thought, I suppose so. What I really wanted was the com.saxonica.xsltextn.ExtensionElementFactory interface to have a default method implementation which could return me the transform(s) within which it is currently being used. The interface here would be a two-way contract between Saxon and extension implementers saying in effect "Saxon needs getExtensionClass​(), and we realize you might want the 'context' in which you're being used, so here is public Transform[] getTransforms(). Once extension element factories as specified within the configuration were recognized by Saxon, each would have to be instantiated by Saxon so that the Transforms[] array could be updated via a setTransforms() method also within the interface. But what's the point in even doing all that when, in order to make that work, Saxon needs to have the extension class name provided up-front in the config in order to instantiate that class so the transforms to be returned by getTransforms() can even be set in the first place? For my purposes, that's a non-starter, and I am sure there are a million other reasons as well as to why it won't work, some of which I may or may not comprehend at the moment.

As far as my goal of not asking the user to do much out of the ordinary when attempting to use my functions is concerned, I have to be realistic. I do have fun thinking about doing things differently, and hopefully to better effect. But the reality is that working with Saxon and writing your own XSLT using third-party extension functions is far from a back-box situation. You're going to need to know how, and be prepared to do, custom configuration of a Saxon config file, specifying certain switches when running the transform, or even using a third-party "Saxon overlay" transformation engine as you just proposed as one option.

In the end, asking the user to copy and paste a bunch of resources/extensionFunction entries into the configuration file is not that big of an ask, and is arguably the most straightforward path. To ease any pain, I could even provide a ConfigurationHelper mini-app which would splice in all my extension function/element specifications within a user's existing config. Just run once and then they're all set.

I appreciate being able to bounce ideas off of you and be schooled or led in a productive direction in the process.

-Tony

RE: Altering a Saxon-EE User's Configuration Within Custom Extension Code After Transform Start - Added by Anthony Bufort 5 months ago

  • Clarification for future reads - just caught a typo in the above - meant to write "black" instead of "back" box, as in something that just works for a user without need for much technical knowledge of how it does on their part.
    (1-5/5)

    Please register to reply