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> * <xslt-processor class="org.apache.cocoon.components.xslt.XSLTProcessorImpl"> * <parameter name="use-store" value="true"/> * <parameter name="transformer-factory" value="org.apache.xalan.processor.TransformerFactoryImpl"/> * </xslt-processor> * </pre> * * The <use-store> 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 <transformer-factory> 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]