Hi Joe,

Thanks for detailling the issues in this class. This URI resolver
lacks tests indeed.

Could you provide a SVN patch that would fix those issues? I would
like that to be fixed before releasing the 1.0.6 version next week.

Also, if you have time to provide a test case, we could add it to the
build process :)

Best regards,
Jerome


2007/10/24, Joe Nellis <[EMAIL PROTECTED]>:
> Greetings again,
>
> There is a bug in the TransformRepresentation.getTransformer() method
> involving the wrong setURIResolver method being called.  The method in
> question:
>
>     public Transformer getTransformer() throws IOException {
>         if (this.transformer == null) {
>             try {
>                 // Prepare the XSLT transformer documents
>                 StreamSource transformSheet = new StreamSource(
>                         getTransformSheet().getStream());
>
>                 // Create a new transformer as they are not thread safe
>                 this.transformer = TransformerFactory.newInstance()
>                         .newTransformer(transformSheet);
>
>                 // Set the URI resolver
>                 transformer.setURIResolver(getURIResolver());
>             } catch (TransformerConfigurationException tce) {
>                 throw new IOException("Transformer configuration exception.
> "
>                         + tce.getMessage());
>             } catch (TransformerFactoryConfigurationError tfce) {
>                 throw new IOException(
>                         "Transformer factory configuration exception. "
>                                 + tfce.getMessage());
>             }
>         }
>
>         return this.transformer;
>     }
>
> The this.transformer assignment calls for an instance of the
> TransformerFactory, then calls for a new Transformer handing it the
> transformsheet in the process.  At this point in execution, compiling of the
> transform sheet is done and any <xsl:include>,<xsl:import> or document()
> functions will use the default URIResolver.  But in this case, the
> URIResolver that is intended to be used is set AFTER the stylesheet is
> compiled, which is after include/import tags need to be resolved.
>
> So what is being used as a URIResolver?  Null is the value, and the XSLT
> spec says that
> if it's null then the base that the XSLT implementers should use is the
> address of the current stylesheet as the base reference.  In some contexts
> of the Transformer, the stylesheet is passed as a file object so the
> transformer implementation has a chance to resolve include/imports when the
> URIResolver is null.  In the TransformRepresentation case, it only sees a
> stream so there is a different default base address, which is usually the
> working address of the program that is creating Transformer objects.  In the
> case of using the ServerServlet, for the most part this base address is
> going to be the application container address.. In the netbeans bundled
> tomcat it resolves to the tomcat bin folder.  With Resin it resolves
> somewhat more correctly to the webapps/application root directory.
>
> The next problem is that Transformer.setURIResolver is for setting the
> resolver for ONLY document() function calls in a stylesheet, which are
> dynamic and resolved at runtime.  Include/import tags are static and
> resolved at compile time.  The TransformerFactory.setURIResolver is the
> correct method, it sets the resolver for include/import and document()
> function.  So the modified code would look like this:
>
>   @Override
>   public Transformer getTransformer() throws IOException {
>     /* There is no way to set the transformer in this override
>      * since their is no protected setTransformer method.
>      * A new Transformer is created for each call.     */
>     Transformer result = null;
>     try {
>       // Prepare the XSLT transformer documents
>       StreamSource transformSheet = new StreamSource(
>           getTransformSheet().getStream());
>
>       // Get a transformer factory.
>       TransformerFactory tfactory = TransformerFactory.newInstance();
>       // Set the URI resolver before compiling the stylesheet
>       // since all it ever sees is a stream, not a file/path object.
>       tfactory.setURIResolver(getURIResolver());
>       // Create a new transformer as they are not thread safe
>       result = tfactory.newTransformer(transformSheet);
>
>     } catch (TransformerConfigurationException tce) {
>       throw new IOException("Transformer configuration exception. "
>           + tce.getMessage());
>     } catch (TransformerFactoryConfigurationError tfce) {
>       throw new IOException(
>           "Transformer factory configuration exception. "
>           + tfce.getMessage());
>     }
>     return result;
>   }
>
> Now the behavior actually invokes the default URIResolver for
> TransformRepresentation, which is the embedded member class ContextResolver.
> Line 184-185 there seems like an error in forgetting to resolve the base
> address:
>
>                 Response response = this.context.getDispatcher().get(
>                         targetRef.toString());
> should be:
>                 Response response = this.context.getDispatcher().get(
>                         targetRef.getTargetRef().toString());
>
> Otherwise the base address is never resolved.  This base address String
> value that is passed into the URIResolver is, I think, exclusively the
> explicitly called base value that is encountered in xslt tags that contain
> xml:base="path to base" attributes. I'm not positive on that. This is about
> where I am right now. I think more test cases are needed for the
> ContextResolver class maybe.  Some transformer implementations may pass the
> base parameter to the resolver as null or as an empty string. Right now
> there is no check for this but I would think they both mean the same thing.
> I'm currently unable to get line 184-185 to return a response with a
> non-null entity even with a valid reference anyway, so I'm still digging
> around.
>
> Right now I suggest using a custom URIResolver when  you need
> includes/imports in your xslt files or  you are running under the
> ServerServlet in a app container.  Unfortunately, there is no
> TransformRepresentation.setURIResolver as it is locked into it's custom
> ContextResolver during construction.  So until this is remedied as well, you
> need to subclass TransformRepresentation anyway and override the entire
> getTransformer() method to accept your custom resolver.
>
> Joe.
>
>

Reply via email to