proyal      2002/06/30 17:52:07

  Modified:    xmlbundle/src/java/org/apache/avalon/excalibur/xml/xslt
                        XSLTProcessorImpl.java
  Log:
  Patch from [EMAIL PROTECTED] to fix #9905
   * Added dependency checks for xsl:import/xsl:include'd files
  
  Revision  Changes    Path
  1.8       +211 -97   
jakarta-avalon-excalibur/xmlbundle/src/java/org/apache/avalon/excalibur/xml/xslt/XSLTProcessorImpl.java
  
  Index: XSLTProcessorImpl.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-avalon-excalibur/xmlbundle/src/java/org/apache/avalon/excalibur/xml/xslt/XSLTProcessorImpl.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- XSLTProcessorImpl.java    4 Jun 2002 08:42:13 -0000       1.7
  +++ XSLTProcessorImpl.java    1 Jul 2002 00:52:07 -0000       1.8
  @@ -10,6 +10,9 @@
   import java.io.File;
   import java.io.IOException;
   import java.util.HashMap;
  +import java.util.List;
  +import java.util.ArrayList;
  +import java.util.Map;
   import javax.xml.transform.Result;
   import javax.xml.transform.Templates;
   import javax.xml.transform.Transformer;
  @@ -27,6 +30,7 @@
   import org.xml.sax.XMLFilter;
   
   import org.apache.avalon.excalibur.xml.XMLizable;
  +
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.ComponentException;
   import org.apache.avalon.framework.component.ComponentManager;
  @@ -39,6 +43,7 @@
   import org.apache.excalibur.source.SourceException;
   import org.apache.excalibur.source.SourceResolver;
   import org.apache.excalibur.source.SourceValidity;
  +import org.apache.excalibur.source.impl.validity.AggregatedValidity;
   import org.apache.excalibur.xmlizer.XMLizer;
   import org.apache.excalibur.store.Store;
   
  @@ -88,12 +93,15 @@
       /** Is incremental processing turned on? (default for Xalan: no) */
       protected boolean incrementalProcessing = false;
   
  -    /** The source resolver */
  +    /** Resolver used to resolve XSLT document() calls, imports and includes */
       protected SourceResolver resolver;
   
       /** The error handler for the transformer */
       protected TraxErrorHandler errorHandler;
   
  +    /** Map of pairs of System ID's / validities of the included stylesheets */
  +    protected Map includesMap = new HashMap();
  +
       /**
        * Compose. Try to get the store
        */
  @@ -101,7 +109,7 @@
         throws ComponentException
       {
           this.manager = manager;
  -        this.errorHandler = new TraxErrorHandler( this.getLogger() );
  +        this.errorHandler = new TraxErrorHandler( getLogger() );
           this.resolver = (SourceResolver)this.manager.lookup( SourceResolver.ROLE );
       }
   
  @@ -160,13 +168,25 @@
                                                        XMLFilter filter )
         throws XSLTProcessorException
       {
  +        return getTransformerHandlerAndValidity( stylesheet, filter 
).getTransfomerHandler();
  +    }
  +
  +    public TransformerHandlerAndValidity getTransformerHandlerAndValidity( Source 
stylesheet )
  +      throws XSLTProcessorException
  +    {
  +        return getTransformerHandlerAndValidity( stylesheet, null );
  +    }
  +
  +    public TransformerHandlerAndValidity getTransformerHandlerAndValidity( Source 
stylesheet, XMLFilter filter )
  +      throws XSLTProcessorException
  +    {
           try
           {
               final String id = stylesheet.getSystemId();
  -            Templates templates = getTemplates(stylesheet, id);
  -            if( templates == null )
  +            TransformerHandlerAndValidity handlerAndValidity = 
getTemplates(stylesheet, id);
  +            if( handlerAndValidity == null )
               {
  -                if( this.getLogger().isDebugEnabled() )
  +                if( getLogger().isDebugEnabled() )
                   {
                       getLogger().debug( "Creating new Templates for " + id );
                   }
  @@ -178,60 +198,66 @@
                   // Set the system ID for the template handler since some
                   // TrAX implementations (XSLTC) rely on this in order to obtain
                   // a meaningful identifier for the Templates instances.
  -                templatesHandler.setSystemId(id);
  +                templatesHandler.setSystemId ( id );
                   if( filter != null )
                   {
                       filter.setContentHandler( templatesHandler );
                   }
   
  -                if( this.getLogger().isDebugEnabled() )
  +                if( getLogger().isDebugEnabled() )
                   {
                       getLogger().debug( "Source = " + stylesheet
                                          + ", templatesHandler = " + templatesHandler 
);
                   }
   
  -                // Process the stylesheet.
  -                sourceToSAX( stylesheet,
  -                             filter != null ? ( ContentHandler ) filter : ( 
ContentHandler ) templatesHandler );
  -
  -                // Get the Templates object (generated during the parsing of
  -                // the stylesheet) from the TemplatesHandler.
  -                templates = templatesHandler.getTemplates();
  -                putTemplates (templates, stylesheet, id);
  +                // Initialize List for included validities
  +                SourceValidity validity = stylesheet.getValidity();
  +                if (validity != null) {
  +                    includesMap.put( id, new ArrayList() );
  +                }
  +
  +                try {
  +                    // Process the stylesheet.
  +                    sourceToSAX( stylesheet,
  +                                 filter != null ? ( ContentHandler ) filter : ( 
ContentHandler ) templatesHandler );
  +
  +                    // Get the Templates object (generated during the parsing of
  +                    // the stylesheet) from the TemplatesHandler.
  +                    Templates t = templatesHandler.getTemplates();
  +                    putTemplates (t, stylesheet, id);
  +
  +                    // Create transformer handler
  +                    TransformerHandler handler = 
this.factory.newTransformerHandler(t);
  +                    handler.getTransformer().setErrorListener( this.errorHandler );
  +
  +                    // Create aggregated validity
  +                    AggregatedValidity aggregated = null;
  +                    if (validity != null) {
  +                        List includes = (List) includesMap.get( id );
  +                        if (includes != null) {
  +                            aggregated = new AggregatedValidity();
  +                            aggregated.add( validity );
  +                            for ( int i = includes.size() - 1; i >= 0; i-- ) {
  +                                aggregated.add( (SourceValidity) 
((Object[])includes.get(i))[1] );
  +                            }
  +                        }
  +                    }
  +
  +                    // Create result
  +                    handlerAndValidity = new TransformerHandlerAndValidity( 
handler, aggregated );
  +                } finally {
  +                    includesMap.remove( id );
  +                }
               }
               else
               {
  -                if( this.getLogger().isDebugEnabled() )
  +                if( getLogger().isDebugEnabled() )
                   {
                       getLogger().debug( "Reusing Templates for " + id );
                   }
               }
   
  -            TransformerHandler handler = 
this.factory.newTransformerHandler(templates);
  -
  -            /* (VG)
  -            From 
http://java.sun.com/j2se/1.4/docs/api/javax/xml/transform/TransformerFactory.html#newTemplates(javax.xml.transform.Source)
  -            Or 
http://xml.apache.org/xalan-j/apidocs/javax/xml/transform/TransformerFactory.html#newTemplates(javax.xml.transform.Source)
  -
  -            "Returns: Templates object capable of being used for transformation
  -            purposes, never null."
  -            if (handler == null) {
  -            if (this.getLogger().isDebugEnabled()) {
  -            getLogger().debug("Re-creating new Templates for " + id);
  -            }
  -
  -            templates = getTransformerFactory().newTemplates(new 
SAXSource(stylesheet.getInputSource()));
  -            putTemplates (templates, stylesheet, id);
  -            handler = getTransformerFactory().newTransformerHandler(templates);
  -            }
  -            */
  -
  -            handler.getTransformer().setErrorListener( this.errorHandler );
  -            return handler;
  -        }
  -        catch( XSLTProcessorException e )
  -        {
  -            throw e;
  +            return handlerAndValidity;
           }
           catch( SAXException e )
           {
  @@ -257,7 +283,6 @@
           if( source instanceof XMLizable )
           {
               ( ( XMLizable ) source ).toSAX( handler );
  -
           }
           else
           {
  @@ -284,18 +309,17 @@
       {
           try
           {
  -            if( this.getLogger().isDebugEnabled() )
  +            if( getLogger().isDebugEnabled() )
               {
  -                getLogger().debug( "XSLTProcessorImpl: transform source = " + source
  +                getLogger().debug( "Transform source = " + source
                                      + ", stylesheet = " + stylesheet
                                      + ", parameters = " + params
                                      + ", result = " + result );
               }
               TransformerHandler handler = getTransformerHandler( stylesheet );
  -            Transformer transformer = handler.getTransformer();
  -
               if( params != null )
               {
  +                Transformer transformer = handler.getTransformer();
                   transformer.clearParameters();
                   String[] names = params.getNames();
                   for( int i = names.length - 1; i >= 0; i-- )
  @@ -303,13 +327,25 @@
                       transformer.setParameter( names[i], params.getParameter( 
names[i] ) );
                   }
               }
  -            if( getLogger().isDebugEnabled() ) this.getLogger().debug( 
"XSLTProcessorImpl: starting transform" );
  -            // FIXME (VG): Is it possible to use Source's toSAX method?
  -            handler.setResult( result );
   
  +            handler.setResult( result );
               sourceToSAX( source, handler );
  -
  -            if( getLogger().isDebugEnabled() ) this.getLogger().debug( 
"XSLTProcessorImpl: transform done" );
  +            if( getLogger().isDebugEnabled() )
  +            {
  +                getLogger().debug( "Transform done" );
  +            }
  +        }
  +        catch (SAXException e)
  +        {
  +            if( e.getException() == null )
  +            {
  +                throw new XSLTProcessorException( "Error in running 
Transformation", e );
  +            }
  +            else
  +            {
  +                getLogger().debug( "Got SAXException. Rethrowing cause exception.", 
e );
  +                throw new XSLTProcessorException( "Error in running 
Transformation", e.getException() );
  +            }
           }
           catch( Exception e )
           {
  @@ -378,67 +414,108 @@
           return _factory;
       }
   
  -    private Templates getTemplates(Source stylesheet, String id)
  -    throws IOException, XSLTProcessorException {
  -        if (!useStore)
  +    private TransformerHandlerAndValidity getTemplates(Source stylesheet, String id)
  +    throws IOException, SourceException, TransformerException {
  +        if (!useStore) {
               return null;
  +        }
   
           // we must augment the template ID with the factory classname since one
           // transformer implementation cannot handle the instances of a
           // template created by another one.
  -        id += factory.getClass().getName();
  +        String key = id + this.factory.getClass().getName();
   
  -        if (getLogger().isDebugEnabled()) getLogger().debug("XSLTProcessorImpl 
getTemplates: stylesheet " + id);
  +        if (getLogger().isDebugEnabled())
  +        {
  +            getLogger().debug("getTemplates: stylesheet " + id);
  +        }
   
  -        Templates templates = null;
  -        // only stylesheets with a validity are stored
  +        SourceValidity newValidity = stylesheet.getValidity();
   
  -        if (store.containsKey(id)) {
  -            Object[] templateAndValidity = (Object[])store.get(id);
  +        // Only stylesheets with validity are stored
  +        if (newValidity == null) {
  +            // Remove an old template
  +            store.remove(key);
  +            return null;
  +        }
   
  -            SourceValidity storedValidity = (SourceValidity)templateAndValidity[1];
  -            int valid = storedValidity.isValid();
  -            boolean isValid = false;
  -            if ( valid == 0 ) {
  -                SourceValidity validity = stylesheet.getValidity();
  -                if ( null != validity) {
  +        // Stored is an array of the templates and the caching time and list of 
includes
  +        Object[] templateAndValidityAndIncludes = (Object[]) store.get(key);
  +        if (templateAndValidityAndIncludes == null) {
  +            // Templates not found in cache
  +            return null;
  +        }
   
  -                    isValid = storedValidity.isValid( validity );
  +        // Check template modification time
  +        SourceValidity storedValidity = (SourceValidity) 
templateAndValidityAndIncludes[1];
  +        int valid = storedValidity.isValid();
  +        boolean isValid;
  +        if ( valid == 0 ) {
  +            isValid = storedValidity.isValid( newValidity );
  +        } else {
  +            isValid = (valid == 1);
  +        }
  +        if ( !isValid ) {
  +            store.remove(key);
  +            return null;
  +        }
   
  +        // Check includes
  +        AggregatedValidity aggregated = null;
  +        List includes = (List)templateAndValidityAndIncludes[2];
  +        if (includes != null) {
  +            aggregated = new AggregatedValidity();
  +            aggregated.add( storedValidity );
  +
  +            for (int i = includes.size() - 1; i >= 0; i--) {
  +                // Every include stored as pair of source ID and validity
  +                Object[] pair = (Object[])includes.get(i);
  +                storedValidity = (SourceValidity)pair[1];
  +                aggregated.add( storedValidity );
  +
  +                valid = storedValidity.isValid();
  +                isValid = false;
  +                if ( valid == 0 ) {
  +                    SourceValidity included = 
resolver.resolveURI((String)pair[0]).getValidity();
  +                    if (included != null) {
  +                        isValid = storedValidity.isValid( included );
  +                    }
  +                } else {
  +                    isValid = (valid == 1);
  +                }
  +                if ( !isValid ) {
  +                    store.remove(key);
  +                    return null;
                   }
  -            } else {
  -                isValid = (valid == 1);
  -            }
  -
  -            if ( isValid ) {
  -                templates = (Templates)templateAndValidity[0];
  -            } else {
  -                // remove an old template if it exists
  -                store.remove(id);
               }
           }
  -        return templates;
  +
  +        TransformerHandler handler = factory.newTransformerHandler(
  +                (Templates)templateAndValidityAndIncludes[0]);
  +        handler.getTransformer().setErrorListener( this.errorHandler );
  +        return new TransformerHandlerAndValidity( handler, aggregated );
       }
   
       private void putTemplates (Templates templates, Source stylesheet, String id)
  -    throws IOException, XSLTProcessorException {
  +      throws IOException
  +    {
           if (!useStore)
               return;
   
           // we must augment the template ID with the factory classname since one
           // transformer implementation cannot handle the instances of a
           // template created by another one.
  -        id += factory.getClass().getName();
  +        String key = id + factory.getClass().getName();
   
           // only stylesheets with a last modification date are stored
           SourceValidity validity = stylesheet.getValidity();
           if ( null != validity ) {
  -
               // Stored is an array of the template and the current time
  -            Object[] templateAndValidity = new Object[2];
  -            templateAndValidity[0] = templates;
  -            templateAndValidity[1] = validity;
  -            store.store(id, templateAndValidity);
  +            Object[] templateAndValidityAndIncludes = new Object[3];
  +            templateAndValidityAndIncludes[0] = templates;
  +            templateAndValidityAndIncludes[1] = validity;
  +            templateAndValidityAndIncludes[2] = includesMap.get(id);
  +            store.store(key, templateAndValidityAndIncludes);
           }
       }
   
  @@ -459,25 +536,27 @@
       public javax.xml.transform.Source resolve( String href, String base )
         throws TransformerException
       {
  -        if( this.getLogger().isDebugEnabled() )
  +        if( getLogger().isDebugEnabled() )
           {
  -            this.getLogger().debug( "resolve(href = " + href +
  +            getLogger().debug( "resolve(href = " + href +
                                       ", base = " + base + "); resolver = " + 
this.resolver );
           }
   
           Source xslSource = null;
           try
           {
  -            if( href.indexOf( ":" ) > 1 )
  +            if( base == null || href.indexOf( ":" ) > 1 )
               {
  +                // Null base - href must be an absolute URL
                   xslSource = this.resolver.resolveURI( href );
               }
  +            else if( href.length() == 0 )
  +            {
  +                // Empty href resolves to base
  +                xslSource = this.resolver.resolveURI( base );
  +            }
               else
               {
  -                // patch for a null pointer passed as base
  -                if( base == null )
  -                    throw new IllegalArgumentException( "Null pointer passed as 
base" );
  -
                   // is the base a file or a real url
                   if( !base.startsWith( "file:" ) )
                   {
  @@ -490,8 +569,8 @@
                       }
                       else
                       {
  -                        xslSource = this.resolver.resolveURI( new StringBuffer( 
base.substring( 0, lastPathElementPos ) )
  -                                                              .append( "/" 
).append( href ).toString() );
  +                        xslSource = this.resolver.resolveURI( base.substring( 0, 
lastPathElementPos )
  +                                                              + "/" + href );
                       }
                   }
                   else
  @@ -504,25 +583,59 @@
   
               InputSource is = getInputSource( xslSource );
   
  -            if( this.getLogger().isDebugEnabled() )
  +            if( getLogger().isDebugEnabled() )
               {
                   getLogger().debug( "xslSource = " + xslSource + ", system id = " + 
xslSource.getSystemId() );
               }
   
  +            // Populate included validities
  +            List includes = (List)includesMap.get(base);
  +            if( includes != null )
  +            {
  +                SourceValidity included = xslSource.getValidity();
  +                if( included != null )
  +                {
  +                    includes.add( new Object[] { xslSource.getSystemId(), 
xslSource.getValidity() } );
  +                }
  +                else
  +                {
  +                    // One of the included stylesheets is not cacheable
  +                    includesMap.remove( base );
  +                }
  +            }
  +
               return new StreamSource( is.getByteStream(), is.getSystemId() );
           }
           catch( SourceException e )
           {
  -            // to obtain the same behaviour as when the resource is
  +            if( getLogger().isDebugEnabled() )
  +            {
  +                getLogger().debug("Failed to resolve " + href
  +                    + "(base = " + base + "), return null", e);
  +            }
  +
  +            // CZ: To obtain the same behaviour as when the resource is
               // transformed by the XSLT Transformer we should return null here.
               return null;
           }
           catch( java.net.MalformedURLException mue )
           {
  +            if( getLogger().isDebugEnabled() )
  +            {
  +                getLogger().debug("Failed to resolve " + href
  +                    + "(base = " + base + "), return null", mue);
  +            }
  +
               return null;
           }
           catch( IOException ioe )
           {
  +            if( getLogger().isDebugEnabled() )
  +            {
  +                getLogger().debug("Failed to resolve " + href
  +                    + "(base = " + base + "), return null", ioe);
  +            }
  +
               return null;
           }
           finally
  @@ -538,7 +651,8 @@
        *
        * @throws IOException if I/O error occured.
        */
  -    private static InputSource getInputSource( Source source ) throws IOException, 
SourceException
  +    private static InputSource getInputSource( Source source )
  +      throws IOException, SourceException
       {
           final InputSource newObject = new InputSource( source.getInputStream() );
           newObject.setSystemId( source.getSystemId() );
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to