Richard R. McKinley wrote:

> Was there any resolution to the random XSLT file locking in Cocoon 2?  
> I search the net but didn't not find out if it was filed as a bug or 
> solved.  You seem to have discovered the most likely reason for the 
> problem.  Is there a patch you could share with me?  It is a constant 
> problem on my server.
>
Today I patched the Cocoon 2.0 source release to slash that annoying 
XSLT file locking bug (see 
http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=100419666331388&w=2). 
After patching, I have not been experiencing any problems regarding file 
locking at all for more than 4 hours with extensive XSLT development, so 
I guess I squished that bug; before patching, file locking annoyed me 
every 5-10 minutes or so.

Attached please find both a patch.diff and an already patched 
org.apache.cocoon.components.xslt.XSLTProcessorImpl.java. Just exchange 
it, recompile the cocoon.jar, exchange your deployed cocoon.jar with the 
new one, enjoy or report back problems ;)

Best regards,

Michael Hartle,
Hartle & Klug GbR

--- cocoon-2.0/src/org/apache/cocoon/components/xslt/XSLTProcessorImpl.java     Thu 
Nov 29 12:16:32 2001
+++ 
+/home/cocoon/cocoon-2.0/src/org/apache/cocoon/components/xslt/XSLTProcessorImpl.java  
+      Thu Dec 13 23:02:18 2001
@@ -38,6 +38,7 @@
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 import java.io.File;
+import java.io.InputStream;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
@@ -236,10 +237,12 @@
         }
       }
       InputSource is = source.getInputSource();
+      InputStream bs = is.getByteStream();
       getLogger().debug("XSLTProcessorImpl: starting transform");
-      transformer.transform(new StreamSource(is.getByteStream(),
+      transformer.transform(new StreamSource(bs,
                                              is.getSystemId()),
                             result);
+      bs.close();
       getLogger().debug("XSLTProcessorImpl: transform done");
       if (result instanceof StreamResult) {
         Writer writer = ((StreamResult)result).getWriter();
/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included  with this distribution in *
 * the LICENSE file.                                                         *
 *****************************************************************************/
package org.apache.cocoon.components.xslt;

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.logger.AbstractLoggable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.resolver.Resolver;
import org.apache.cocoon.components.store.Store;
import org.apache.cocoon.environment.Source;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.util.ClassUtils;
import org.apache.cocoon.util.TraxErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import javax.xml.transform.*;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TemplatesHandler;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

/**
 * This class defines the implementation of the {@link XSLTProcessor}
 * component.
 *
 * To configure it, add the following lines in the
 * <file>cocoon.xconf</file> file:
 *
 * <pre>
 * &lt;xslt-processor class="org.apache.cocoon.components.xslt.XSLTProcessorImpl"&gt;
 *    &lt;parameter name="use-store" value="true"/&gt;
 *    &lt;parameter name="transformer-factory" 
value="org.apache.xalan.processor.TransformerFactoryImpl"/&gt;
 * &lt;/xslt-processor&gt;
 * </pre>
 *
 * The &lt;use-store&gt; configuration forces the transformer to put the
 * <code>Templates</code> generated from the XSLT stylesheet into the
 * <code>Store</code>. This property is true by default.
 * <p>
 * The &lt;transformer-factory&gt; configuration tells the transformer to use a 
particular
 * implementation of <code>javax.xml.transform.TransformerFactory</code>. This allows 
to force
 * the use of a given TRAX implementation (e.g. xalan or saxon) if several are 
available in the
 * classpath. If this property is not set, the transformer uses the standard TRAX 
mechanism
 * (<code>TransformerFactory.newInstance()</code>).
 *
 * @author <a href="mailto:[EMAIL PROTECTED]";>Ovidiu Predescu</a>
 * @version 1.0
 * @since   July 11, 2001
 */
public class XSLTProcessorImpl
  extends AbstractLoggable
  implements XSLTProcessor, Composable, Disposable, Configurable, URIResolver, 
Component
{
  protected ComponentManager manager;

  /** The store service instance */
  Store store;

  /** The trax TransformerFactory */
  SAXTransformerFactory tfactory;
  
  /** The factory class used to create tfactory */
  Class tfactoryClass;

  /** Is the store turned on? (default is on) */
  boolean useStore = true;
  /** Is incremental processing turned on? (default for Xalan: no) */
  boolean incrementalProcessing = false;

  SourceResolver resolver;

  /** the Entity Resolver */
  protected Resolver entityResolver;

  public void compose(ComponentManager manager)
    throws ComponentException
  {
    this.manager = manager;
    getLogger().debug("XSLTProcessorImpl component initialized.");
    store = (Store)manager.lookup(Store.ROLE);
    getLogger().debug("Looking up " + Resolver.ROLE);
    this.entityResolver = (Resolver)manager.lookup(Resolver.ROLE);
  }


  public void dispose()
  {
    if (this.manager != null)
      this.manager.release((Component)store);
  }

  public void configure(Configuration conf)
    throws ConfigurationException
  {
    Parameters params = Parameters.fromConfiguration(conf);
    useStore = params.getParameterAsBoolean("use-store", true);
    incrementalProcessing = params.getParameterAsBoolean("incremental-processing", 
false);
    
    String factoryName = params.getParameter("transformer-factory", null);
    
    if (factoryName == null) {
      // Will use default TRAX mechanism
      this.tfactoryClass = null;
      
    } else {
      // Will use specific class
      getLogger().debug("Using factory " + factoryName);
      try {
        this.tfactoryClass = ClassUtils.loadClass(factoryName);
      } catch(ClassNotFoundException cnfe) {
        throw new ConfigurationException("Cannot load TransformerFactory class", cnfe);
      }
    
      if (! TransformerFactory.class.isAssignableFrom(tfactoryClass)) {
        throw new ConfigurationException("Class " + factoryName + " isn't a 
TransformerFactory");
      }
    }
  }

  public TransformerHandler getTransformerHandler(Source stylesheet)
    throws ProcessingException
  {
    return getTransformerHandler(stylesheet, null);
  }

  public TransformerHandler getTransformerHandler(Source stylesheet,
                                                  XMLFilter filter)
    throws ProcessingException
  {
    try {
      Templates templates = getTemplates(stylesheet);
      if(templates == null) {
        InputSource is = stylesheet.getInputSource();
        getLogger().debug("Creating new Templates in " + this + " for " + is);
        if (is.getSystemId() != null)
          getLogger().debug("  with system id " + is.getSystemId());

        //templates = getTransformerFactory().newTemplates(new SAXSource(is));

        // Create a Templates ContentHandler to handle parsing of the
        // stylesheet.
        TemplatesHandler templatesHandler
          = getTransformerFactory().newTemplatesHandler();

        // Create an XMLReader and set its ContentHandler.
        XMLReader reader = XMLReaderFactory.createXMLReader();
        reader.setFeature("http://xml.org/sax/features/namespace-prefixes";,
                          true);

        if (filter != null) {
          filter.setParent(reader);
          filter.setContentHandler(templatesHandler);
        }
        else
          reader.setContentHandler(templatesHandler);
        if(this.entityResolver != null)
            reader.setEntityResolver(this.entityResolver);

        getLogger().debug("InputSource = " + is
                          + ", templatesHandler = " + templatesHandler
                          + ", reader = " + reader);
        // Parse the stylesheet.
        reader.parse(is);

        // Get the Templates object (generated during the parsing of
        // the stylesheet) from the TemplatesHandler.
        templates = templatesHandler.getTemplates();
        putTemplates (templates, stylesheet);
      } else {
        getLogger().debug("Reusing Templates in " + this + " for "
                          + stylesheet.getInputSource().getSystemId());
      }

      TransformerHandler handler
        = getTransformerFactory().newTransformerHandler(templates);
      if (handler == null) {
        /* If there is a problem in getting the handler, try using a
         * brand new Templates object */
        getLogger().debug("Re-creating new Templates in " + this + " for"
                          + stylesheet.getInputSource().getSystemId());
        InputSource is = stylesheet.getInputSource();
        templates = getTransformerFactory().newTemplates(new SAXSource(is));
        putTemplates (templates, stylesheet);
        handler = getTransformerFactory().newTransformerHandler(templates);
      }

      handler.getTransformer()
        .setErrorListener(new TraxErrorHandler(getLogger()));
      return handler;
    }
    catch (Exception e) {
      throw new ProcessingException("Error in creating Transform Handler", e);
    }
  }

  public void transform(Source source, Source stylesheet, Parameters params,
                        Result result)
    throws ProcessingException
  {
    try {
      getLogger().debug("XSLTProcessorImpl: transform source = " + source
                        + ", stylesheet = " + stylesheet
                        + ", parameters = " + params
                        + ", result = " + result);
      TransformerHandler handler = getTransformerHandler(stylesheet);
      Transformer transformer = handler.getTransformer();

      if (params != null) {
        transformer.clearParameters();
        String[] names = params.getNames();
        for (int i = names.length -1 ; i >= 0; i--) {
          transformer.setParameter(names[i], params.getParameter(names[i]));
        }
      }
      InputSource is = source.getInputSource();
      InputStream bs = is.getByteStream();
      getLogger().debug("XSLTProcessorImpl: starting transform");
      transformer.transform(new StreamSource(bs,
                                             is.getSystemId()),
                            result);
      bs.close();
      getLogger().debug("XSLTProcessorImpl: transform done");
      if (result instanceof StreamResult) {
        Writer writer = ((StreamResult)result).getWriter();
        getLogger().debug("XSLTProcessorImpl: transform result = "
                          + writer);
        if (writer instanceof StringWriter) {
          StringBuffer stringBuffer = ((StringWriter)writer).getBuffer();
          getLogger().debug("XSLTProcessorImpl: transform result = "
                            + stringBuffer);
        }
      }
    }
    catch (Exception e) {
      throw new ProcessingException("Error in running Transformation", e);
    }
  }

  /**
   * Helper for TransformerFactory.
   */
  private SAXTransformerFactory getTransformerFactory() throws Exception
  {
    if(tfactory == null) {
      if (tfactoryClass == null) {
        tfactory = (SAXTransformerFactory)TransformerFactory.newInstance();
      } else {
        tfactory = (SAXTransformerFactory)tfactoryClass.newInstance();
      }
      tfactory.setErrorListener(new TraxErrorHandler(getLogger()));
      tfactory.setURIResolver(this);
      // TODO: If we will support this feature with a different
      // transformer than Xalan we'll have to set that corresponding
      // feature
      if 
(tfactory.getClass().getName().equals("org.apache.xalan.processor.TransformerFactoryImpl"))
 {
         tfactory.setAttribute("http://xml.apache.org/xalan/features/incremental";,
                               new Boolean (incrementalProcessing));
      }
    }
    return tfactory;
  }

  private Templates getTemplates(Source stylesheet)
    throws IOException, ProcessingException
  {
    Templates templates = null;

    if (useStore == false)
      return null;

    InputSource is = stylesheet.getInputSource();
    getLogger().debug("XSLTProcessorImpl getTemplates: stylesheet "
                      + is.getSystemId());

    // only stylesheets with a last modification date are stored
    if (stylesheet.getLastModified() != 0) {

      // Stored is an array of the template and the caching time
      if (store.containsKey(is.getSystemId())) {
        Object[] templateAndTime
          = (Object[])store.get(is.getSystemId());

        if(templateAndTime != null && templateAndTime[1] != null) {
          long storedTime = ((Long)templateAndTime[1]).longValue();

          if (storedTime < stylesheet.getLastModified()) {
            store.remove(is.getSystemId());
          }
          else {
            templates = (Templates)templateAndTime[0];
          }
        }
      }
    }
    else {
      // remove an old template if it exists
      if (store.containsKey(is.getSystemId())) {
        store.remove(is.getSystemId());
      }
    }
   return templates;
  }

  private void putTemplates (Templates templates, Source stylesheet)
    throws IOException, ProcessingException
  {
    if (useStore == false)
      return;

    // only stylesheets with a last modification date are stored
    if (stylesheet.getLastModified() != 0) {

      // Stored is an array of the template and the current time
      Object[] templateAndTime = new Object[2];
      templateAndTime[0] = templates;
      templateAndTime[1] = new Long(stylesheet.getLastModified());
      store.hold(stylesheet.getInputSource().getSystemId(), templateAndTime);
    }
  }

  /**
   * Called by the processor when it encounters
   * an xsl:include, xsl:import, or document() function.
   *
   * @param href An href attribute, which may be relative or absolute.
   * @param base The base URI in effect when the href attribute
   * was encountered.
   *
   * @return A Source object, or null if the href cannot be resolved,
   * and the processor should try to resolve the URI itself.
   *
   * @throws TransformerException if an error occurs when trying to
   * resolve the URI.
   */
  public javax.xml.transform.Source resolve(String href, String base)
    throws TransformerException
  {
    getLogger().debug("XSLTProcessorImpl: resolve(href = " + href
                      + ", base = " + base + "); resolver = " + resolver);

    try {
      Source xslSource;
      if (href.indexOf(":") > 1) {
        xslSource = resolver.resolve(href);
      }
      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:")) {
          int lastPathElementPos = base.lastIndexOf('/');
          if (lastPathElementPos == -1) {
            // this should never occur as the base should
            // always be protocol:/....
            return null; // we can't resolve this
          }
          else {
            xslSource = resolver.resolve(new StringBuffer(base.substring(0, 
lastPathElementPos))
                                         .append("/").append(href).toString());
          }
        }
        else {
          File parent = new File(base.substring(5));
          File parent2 = new File(parent.getParentFile(), href);
          xslSource = resolver.resolve(parent2.toURL().toExternalForm());
        }
      }
      InputSource is = xslSource.getInputSource();
      getLogger().debug("xslSource = " + xslSource
                        + ", system id = " + is.getSystemId());
      return new StreamSource(is.getByteStream(),
                              is.getSystemId());
    } catch (ResourceNotFoundException rnfe) {
        // 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) {
        return null;
    } catch (java.io.IOException ioe) {
        return null;
    } catch (org.xml.sax.SAXException se) {
        throw new TransformerException(se);
    } catch (ProcessingException pe) {
        throw new TransformerException(pe);
    }
  }

  public void setSourceResolver(SourceResolver resolver)
  {
    this.resolver = resolver;
  }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to