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]