0
votes

I have recently obtained a trial license for Saxon-PE and wish to use this version of Saxon within Camel. I downloaded the Saxon-PE-9.6.0.8 jars and have included them into my project via maven. I am using Camel 2.16.0. I have tried many approaches to this, but I have made the most headway by using Camel's "?transformerFactory=..." option and passing it Saxon's ProfessionalTransformerFactoryImpl, which is registered as a bean in my Spring config.

When starting my application, the route initialization with the xslt transformation fails with the following stack trace:

Caused by: java.lang.IllegalStateException: Error pre-loading Saxon classes. Make sure you have saxon on the classpath, and the classloader can load the following two classes: net.sf.saxon.event.Receiver, net.sf.saxon.serialize.MessageWarner. at org.apache.camel.builder.xml.XsltBuilder.doStart(XsltBuilder.java:618) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.util.ServiceHelper.startService(ServiceHelper.java:74) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.component.xslt.XsltEndpoint.doStart(XsltEndpoint.java:396) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.impl.DefaultCamelContext.startService(DefaultCamelContext.java:3219) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.impl.DefaultCamelContext.doAddService(DefaultCamelContext.java:1209) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.impl.DefaultCamelContext.addService(DefaultCamelContext.java:1170) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.impl.DefaultCamelContext.addService(DefaultCamelContext.java:1166) ~[camel-core-2.16.0.jar:2.16.0] at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:583) ~[camel-core-2.16.0.jar:2.16.0] ... 38 common frames omitted Caused by: java.lang.NoSuchMethodException: net.sf.saxon.jaxp.TransformerImpl.setMessageEmitter(net.sf.saxon.event.Receiver) at java.lang.Class.getMethod(Class.java:1786) ~[na:1.8.0_45] at org.apache.camel.builder.xml.XsltBuilder.doStart(XsltBuilder.java:616) ~[camel-core-2.16.0.jar:2.16.0] ... 47 common frames omitted

The issue is that the setMessageEmitter() method does not exist in the JAXP TransformerImpl.

If anybody has any experience integrating Saxon-PE/EE with camel, I would appreciate any input. I need Saxon-PE in order to make use of external function calls from my xsl stylesheets. Previously, in the same project, I have used with Saxon-HE (via the camel-saxon maven dependency) without any trouble. It is only upon switching to Saxon-PE that this problem occurs.

I can provide any other details that might help. Thanks in advance.

2

2 Answers

2
votes

Saxon basically has three tiers of interfaces. Tier 1 is public APIs, including the JAXP and XQJ interfaces and the s9api interface. We try very hard to keep these compatible across releases. Tier 2 is "system programming interfaces" - things that are a little lower-level, but which are frequently needed by integrators - examples are the NodeInfo and Receiver interfaces. There are usually a few small changes to SPIs between Saxon major releases (e.g. 9.5 to 9.6, or 9.6 to 9.7). With maintenance releases (e.g. 9.5.0.7 to 9.5.0.8) we try very hard to avoid any incompatible changes. We try to avoid gratuitous changes to SPIs even at major releases, but we will make a change if it is architecturally necessary. For example, until 9.6 we exposed location information (system id, line and column number) in the Receiver interface as a globally unique integer. But the introduction of separately-compiled packages in XSLT 3.0, and hence in Saxon 9.7, meant that this design became unworkable, so we switched to passing a Location object instead. Although these changes are minor, they are enough to ensure that an application that uses Saxon, and strays outside the stable public APIs, typically needs to at least be recompiled to work with a new Saxon version.

The third tier consists of internal APIs: an example is the structure of the expression tree built by the compiler. Although some third party applications (e.g. debuggers or performance profilers) may need to access such interfaces, we make no attempt to keep them compatible from one major release to the next.

I think the particular change between 9.5 and 9.6 that affects Camel is probably due to the fact that the internal Controller class no longer serves as the implementation class of the JAXP Transformer interface (so casting Transformer to Controller no longer works). The problems of maintaining the Controller in this role, when it also performed various other functions, had slowly increased over the years; at the same time the JAXP transformation interface (which is firmly based on XSLT 1.0) is increasingly peripheral to the new things Saxon is doing and the time had come to prevent it acting as a constraint on our internal design.

I have always taken the view that we have to balance the need to make it easy for users to move forward and the need to prevent structural decay (and hence unreliability) in the code base. As the product has matured, stability has become increasingly important, but new facilities like streaming and modular compilation are architecturally disruptive, and we don't want to stand still.

We are always prepared to make old releases available to users who have genuine difficulties moving forward.

1
votes

Apache Camel 2.16.x does not support Saxon 9.6. We support the version of Saxon we test against which afair is 9.5.

Its not our fault that the Saxon team changed and broke their APIs. So we cannot easily upgrade and allow users to run with the free version 9.5.