View Javadoc
1   /**
2    * Copyright (C) 2014-2018 Philip Helger (www.helger.com)
3    * philip[at]helger[dot]com
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *         http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package com.helger.schematron.saxon;
18  
19  import javax.annotation.Nonnull;
20  import javax.annotation.Nullable;
21  import javax.annotation.concurrent.Immutable;
22  import javax.xml.transform.ErrorListener;
23  import javax.xml.transform.TransformerConfigurationException;
24  import javax.xml.transform.TransformerFactory;
25  import javax.xml.transform.TransformerFactoryConfigurationError;
26  import javax.xml.transform.URIResolver;
27  
28  import com.helger.commons.CGlobal;
29  import com.helger.commons.exception.InitializationException;
30  import com.helger.commons.lang.ClassLoaderHelper;
31  import com.helger.xml.transform.DefaultTransformURIResolver;
32  import com.helger.xml.transform.LoggingTransformErrorListener;
33  
34  import net.sf.saxon.lib.FeatureKeys;
35  
36  /**
37   * A special {@link TransformerFactory} handler that prefers Saxon's
38   * {@link TransformerFactory} before calling the SPI version
39   * <code>TransformerFactory.newInstance ()</code>. This is mainly to solve the
40   * interoperability issue when using Xalan and Saxon together in the class path.
41   *
42   * @author Philip Helger
43   */
44  @Immutable
45  public final class SchematronTransformerFactory
46  {
47    public static final String SAXON_TRANSFORMER_FACTORY_CLASS = "net.sf.saxon.TransformerFactoryImpl";
48    private static final TransformerFactory s_aDefaultFactory;
49  
50    static
51    {
52      s_aDefaultFactory = createTransformerFactorySaxonFirst ((ClassLoader) null,
53                                                              new LoggingTransformErrorListener (CGlobal.DEFAULT_LOCALE),
54                                                              new DefaultTransformURIResolver ());
55    }
56  
57    private SchematronTransformerFactory ()
58    {}
59  
60    /**
61     * @return The default "Saxon first" {@link TransformerFactory}. Never
62     *         <code>null</code>.
63     */
64    @Nonnull
65    public static TransformerFactory getDefaultSaxonFirst ()
66    {
67      return s_aDefaultFactory;
68    }
69  
70    /**
71     * Create a new {@link TransformerFactory} trying to invoke the Saxon
72     * implementation first using the class
73     * {@value #SAXON_TRANSFORMER_FACTORY_CLASS}.
74     *
75     * @param aClassLoader
76     *        The optional class loader to be used. May be <code>null</code>.
77     * @param aErrorListener
78     *        An optional XSLT error listener to be used. May be
79     *        <code>null</code>.
80     * @param aURIResolver
81     *        An optional XSLT URI resolver to be used. May be <code>null</code>.
82     * @return A new {@link TransformerFactory} and not <code>null</code>.
83     * @throws InitializationException
84     *         In case initialization fails.
85     */
86    @Nonnull
87    public static TransformerFactory createTransformerFactorySaxonFirst (@Nullable final ClassLoader aClassLoader,
88                                                                         @Nullable final ErrorListener aErrorListener,
89                                                                         @Nullable final URIResolver aURIResolver)
90    {
91      TransformerFactory aFactory;
92      try
93      {
94        // Try Saxon first
95        final ClassLoader aEffectiveClassLoader = aClassLoader != null ? aClassLoader
96                                                                       : ClassLoaderHelper.getContextClassLoader ();
97        aFactory = TransformerFactory.newInstance (SAXON_TRANSFORMER_FACTORY_CLASS, aEffectiveClassLoader);
98  
99        // Debug/testing only
100       if (false)
101         aFactory.setFeature (FeatureKeys.TRACE_OPTIMIZER_DECISIONS, true);
102       if (false)
103         aFactory.setFeature (FeatureKeys.COMPILE_WITH_TRACING, true);
104       if (false)
105         aFactory.setAttribute (FeatureKeys.XSLT_VERSION, "2.0");
106     }
107     catch (final TransformerFactoryConfigurationError | TransformerConfigurationException ex)
108     {
109       try
110       {
111         // Try default afterwards
112         aFactory = TransformerFactory.newInstance ();
113       }
114       catch (final TransformerFactoryConfigurationError ex2)
115       {
116         throw new InitializationException ("Failed to create XML TransformerFactory", ex2);
117       }
118     }
119 
120     if (aErrorListener != null)
121       aFactory.setErrorListener (aErrorListener);
122     if (aURIResolver != null)
123       aFactory.setURIResolver (aURIResolver);
124     return aFactory;
125   }
126 }