Author: thorsten
Date: Tue Dec 20 16:08:56 2005
New Revision: 358157
URL: http://svn.apache.org/viewcvs?rev=358157&view=rev
Log:
Fixed issue with the contract result transformation that prevented to use
xsl:include and similar commands by implementing an URIResolver. As well added
a system id and a cached transformer. Further enhanced the error handling
Modified:
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBeanDOMImpl.java
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java
Modified:
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java
URL:
http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java?rev=358157&r1=358156&r2=358157&view=diff
==============================================================================
---
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java
(original)
+++
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBean.java
Tue Dec 20 16:08:56 2005
@@ -101,15 +101,16 @@
public abstract void setContractImpl(String contractUri) throws Exception;
/**
- * setContractImpl(Document _contractImpl)
+ * setContractImpl(Document _contractImpl,systemID)
*
* This method invokes the setting of the actual contract implementation
via
* a document.
*
- * @param contractUri
+ * @param _contractImpl
+ * @param systemID
* @throws Exception
*/
- public abstract void setContractImpl(Document _contractImpl)
+ public abstract void setContractImpl(Document _contractImpl, String
systemID)
throws Exception;
/**
Modified:
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBeanDOMImpl.java
URL:
http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBeanDOMImpl.java?rev=358157&r1=358156&r2=358157&view=diff
==============================================================================
---
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBeanDOMImpl.java
(original)
+++
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/ContractBeanDOMImpl.java
Tue Dec 20 16:08:56 2005
@@ -21,17 +21,18 @@
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.forrest.dispatcher.lenya.xml.NamespaceHelper;
-import org.apache.forrest.dispatcher.transformation.DispatcherTransformer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -109,6 +110,10 @@
private HashMap parameterHelper;
+ private String m_systemID;
+
+ private URIResolver m_uriResolver;
+
/**
* The ContractBean contains all fields to work with contracts. It is a
* helper bean.
@@ -122,8 +127,9 @@
* @param parameterHelper
* @throws ParserConfigurationException
*/
- public ContractBeanDOMImpl(ServiceManager manager, HashMap parameterHelper)
+ public ContractBeanDOMImpl(ServiceManager manager, HashMap
parameterHelper,URIResolver uriResolver)
throws ParserConfigurationException {
+ m_uriResolver=uriResolver;
this.manager = manager;
dispatcherHelper = new DispatcherHelper(manager);
this.parameterHelper = parameterHelper;
@@ -165,6 +171,7 @@
* @see
org.apache.forrest.dispatcher.ContractBeanInterface#setContractImpl(java.lang.String)
*/
public void setContractImpl(String contractUri) throws Exception {
+ m_systemID = contractUri;
Document _contractImpl = dispatcherHelper.getDocument(contractUri);
this.contractImpl = _contractImpl;
contractImplHelper(this.contractImpl);
@@ -175,7 +182,9 @@
*
* @see
org.apache.forrest.dispatcher.ContractBeanInterface#setContractImpl(org.w3c.dom.Document)
*/
- public void setContractImpl(Document _contractImpl) throws Exception {
+ public void setContractImpl(Document _contractImpl, String systemID)
+ throws Exception {
+ m_systemID = systemID;
this.contractImpl = _contractImpl;
contractImplHelper(this.contractImpl);
}
@@ -215,12 +224,13 @@
.getElementsByTagName("xsl:stylesheet");
if (list_transformer.getLength() == 1) {
Node node = list_transformer.item(0);
- TransformerFactory tFactory = TransformerFactory
+ TransformerFactory transFact = TransformerFactory
.newInstance();
DOMSource stylesource = new DOMSource(node);
- Transformer transformer = tFactory
- .newTransformer(stylesource);
- if (transformer == null)
+ stylesource.setSystemId(m_systemID);
+ transFact.setURIResolver(m_uriResolver);
+ Templates cachedXSLT = transFact.newTemplates(stylesource);
+ if (cachedXSLT == null)
throw new DispatcherException(
DispatcherException.ERROR_500
+ "\n"
@@ -240,6 +250,7 @@
* Set default properties
*/
// default forrest properties
+ Transformer transformer = cachedXSLT.newTransformer();
Node defaultVariables =
org.apache.forrest.dispatcher.util.SourceUtil
.readDOM("cocoon://test-props", this.manager);
transformer.setParameter("defaultVariables",
Modified:
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java
URL:
http://svn.apache.org/viewcvs/forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java?rev=358157&r1=358156&r2=358157&view=diff
==============================================================================
---
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java
(original)
+++
forrest/trunk/whiteboard/plugins/org.apache.forrest.plugin.internal.structurer/src/java/org/apache/forrest/dispatcher/transformation/DispatcherTransformer.java
Tue Dec 20 16:08:56 2005
@@ -16,16 +16,19 @@
*/
package org.apache.forrest.dispatcher.transformation;
+import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.parameters.Parameters;
@@ -39,6 +42,8 @@
import org.apache.cocoon.xml.XMLUtils;
import org.apache.cocoon.xml.dom.DOMBuilder;
import org.apache.cocoon.xml.dom.DOMUtil;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.xml.xpath.XPathProcessor;
import org.apache.forrest.dispatcher.ContractBean;
@@ -52,11 +57,12 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
public class DispatcherTransformer extends AbstractSAXTransformer implements
- Disposable, CacheableProcessingComponent {
+ Disposable, CacheableProcessingComponent, URIResolver {
/* Node and attribute names */
/**
@@ -65,7 +71,7 @@
* format for the request.
*
* <pre>
- * <<strong>forrest:view</strong>
format="html"/>
+ * <<strong>forrest:view</strong>
format="html"/>
* </pre>
*/
public static final String STRUCTURER_ELEMENT = "view";
@@ -77,7 +83,7 @@
* <strong>format</strong>.
*
* <pre>
- * <forrest:view
<strong>format</strong>="html"/>
+ * <forrest:view
<strong>format</strong>="html"/>
* </pre>
*/
public static final String STRUCTURER_FORMAT_ATTRIBUTE = "type";
@@ -94,7 +100,7 @@
* layout via e.g. css. In html for example
*
* <pre>
- * <forrest:hook name="test"/>
+ * <forrest:hook name="test"/>
* </pre>
*
* <p>
@@ -102,7 +108,7 @@
* </p>
*
* <pre>
- * <div id="test"/>
+ * <div id="test"/>
* </pre>
*/
public static final String DISPATCHER_HOOK_ELEMENT = "hook";
@@ -112,7 +118,7 @@
* css. In html for example
*
* <pre>
- * <forrest:css url="pelt.basic.css"
media="screen" theme="Pelt"/>
+ * <forrest:css url="pelt.basic.css"
media="screen" theme="Pelt"/>
* </pre>
*
* <p>
@@ -120,7 +126,7 @@
* </p>
*
* <pre>
- * <link media="screen"
href="../themes/pelt.basic.css" title="Pelt"
rel="stylesheet" type="text/css" />
+ * <link media="screen"
href="../themes/pelt.basic.css" title="Pelt"
rel="stylesheet" type="text/css" />
* </pre>
*/
public static final String DISPATCHER_CSS_ELEMENT = "css";
@@ -181,8 +187,12 @@
private HashMap parameterHelper;
+ private SourceResolver m_resolver;
+
public static final String HOOKS_TRANSFORMER_PARAMETER =
"hooksTransformer";
+
public static final String PATH_PARAMETER = "path";
+
/**
* Constructor Set the namespace
*/
@@ -206,7 +216,7 @@
* Generate the validity object.
*
* @return The generated validity object or <code>null</code> if the
- * component is currently not cacheable.
+ * component is currently not cacheable.
*/
public SourceValidity getValidity() {
return null;
@@ -224,8 +234,10 @@
*/
public void dispose() {
if (null != this.manager) {
+ this.manager.release(m_resolver);
this.manager = null;
}
+ m_resolver = null;
insideProperties = false;
super.dispose();
}
@@ -236,7 +248,7 @@
public void recycle() {
localRecycle();
super.recycle();
-
+
}
/**
@@ -252,6 +264,7 @@
this.dispatcherHelper = new DispatcherHelper(manager);
this.processor = (XPathProcessor) this.manager
.lookup(XPathProcessor.ROLE);
+ m_resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
} catch (Exception e) {
String error = "dispatcherError:\n Could not set up the
dispatcherHelper!\n DispatcherStack: "
+ e;
@@ -259,7 +272,7 @@
throw new ProcessingException(error);
}
storedPrefixMap = new HashMap();
- this.parameterHelper= new HashMap();
+ this.parameterHelper = new HashMap();
this.allowMarkup = Boolean.getBoolean(parameters.getParameter(
DISPATCHER_ALLOW_MARKUP, null));
@@ -271,15 +284,17 @@
getLogger().error(error);
throw new ProcessingException(error);
}
- parameterHelper.put(STRUCTURER_FORMAT_ATTRIBUTE,requestedFormat);
- /*this.pathXSL = parameters.getParameter(PATH_PARAMETER,null);
- if (this.pathXSL==null){
- String warning = "dispatcherError:\n"
- + "You did not set up the \"path\" parameter in the sitemap,
we are not going to support default variables in contracts."
- + " Meaning that you are not able to use e.g. $skin-img-dir,
if you do the contract bean implementation will throw an exception.";
- getLogger().warn(warning);
- }
- parameterHelper.put(PATH_PARAMETER,pathXSL);*/
+ parameterHelper.put(STRUCTURER_FORMAT_ATTRIBUTE, requestedFormat);
+ /*
+ * this.pathXSL = parameters.getParameter(PATH_PARAMETER,null); if
+ * (this.pathXSL==null){ String warning = "dispatcherError:\n" + "You
+ * did not set up the \"path\" parameter in the sitemap, we are not
+ * going to support default variables in contracts." + " Meaning that
+ * you are not able to use e.g. $skin-img-dir, if you do the contract
+ * bean implementation will throw an exception.";
+ * getLogger().warn(warning); }
+ * parameterHelper.put(PATH_PARAMETER,pathXSL);
+ */
this.hooksXSL = parameters.getParameter(HOOKS_TRANSFORMER_PARAMETER,
null);
try {
@@ -294,7 +309,7 @@
this.structurerTransformer = dispatcherHelper
.createTransformer(stylesheet);
}
- parameterHelper.put(HOOKS_TRANSFORMER_PARAMETER,hooksXSL);
+ parameterHelper.put(HOOKS_TRANSFORMER_PARAMETER, hooksXSL);
} catch (Exception e) {
String error = "dispatcherError:\n"
+ "Could not set up the \"hooks transformer\".\n\n
DispatcherStack:\n "
@@ -305,7 +320,7 @@
}
/**
- * Cleanup the transformer
+ * Cleanup the transformer
*/
private void localRecycle() {
this.processor = null;
@@ -314,6 +329,7 @@
this.hooksXSL = null;
this.structurerTransformer = null;
this.insideProperties = false;
+ this.m_resolver = null;
}
public void startElement(String uri, String name, String raw,
@@ -575,10 +591,11 @@
private void contractProcessingStart(Attributes attr) throws SAXException {
try {
if (contract == null)
- contract = new
ContractBeanDOMImpl(this.manager,parameterHelper);
+ contract = new ContractBeanDOMImpl(this.manager,
+ parameterHelper,(URIResolver)this);
else
contract.initialize();
- } catch (ParserConfigurationException e) {
+ } catch (Exception e) {
String error = DispatcherException.ERROR_500 + "\n"
+ "component: ContractBean" + "\n"
+ "message: Could not setup contractBean." + "\n" + "\n\n"
@@ -597,7 +614,7 @@
try {
Document doc =
org.apache.forrest.dispatcher.util.SourceUtil
.readDOM(contractUri, this.manager);
- contract.setContractImpl(doc);
+ contract.setContractImpl(doc, contractUri);
// contract.setContractImpl(contractUri);
} catch (Exception e) {
String error = "dispatcherError: "
@@ -715,8 +732,8 @@
location = "result" + location;
else
location = "result/" + location;
- Node xpathNode= DOMUtil.getSingleNode(rootNode,
location,
- this.processor);
+ Node xpathNode = DOMUtil.getSingleNode(rootNode,
+ location, this.processor);
if (xpathNode != null) {
// add everything *within* the forrest:part element
appendChildToResultIterator(root, finalContent,
@@ -902,6 +919,112 @@
+ pre + " uri: " + uri + " ]");
this.dispatcherBuilder.startPrefixMapping(pre, uri);
}
+ }
+
+ public javax.xml.transform.Source resolve(String href, String base)
+ throws TransformerException {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug(
+ "resolve(href = " + href + ", base = " + base
+ + "); resolver = " + m_resolver);
+ }
+
+ Source xslSource = null;
+ try {
+ if (base == null || href.indexOf(":") > 1) {
+ // Null base - href must be an absolute URL
+ xslSource = m_resolver.resolveURI(href);
+ } else if (href.length() == 0) {
+ // Empty href resolves to base
+ xslSource = m_resolver.resolveURI(base);
+ } else {
+ // is the base a file or a real m_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 = m_resolver.resolveURI(base.substring(0,
+ lastPathElementPos)
+ + "/" + href);
+ }
+ } else {
+ File parent = new File(base.substring(5));
+ File parent2 = new File(parent.getParentFile(), href);
+ xslSource = m_resolver.resolveURI(parent2.toURL()
+ .toExternalForm());
+ }
+ }
+
+ InputSource is = getInputSource(xslSource);
+
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug(
+ "xslSource = " + xslSource + ", system id = "
+ + xslSource.getURI());
+ }
+
+// if (m_checkIncludes) {
+// // Populate included validities
+// List includes = (List) m_includesMap.get(base);
+// if (includes != null) {
+// SourceValidity included = xslSource.getValidity();
+// if (included != null) {
+// includes.add(new Object[] { xslSource.getURI(),
+// xslSource.getValidity() });
+// } else {
+// // One of the included stylesheets is not cacheable
+// m_includesMap.remove(base);
+// }
+// }
+// }
+
+ return new StreamSource(is.getByteStream(), is.getSystemId());
+ } catch (SourceException e) {
+ 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 {
+ m_resolver.release(xslSource);
+ }
+ }
+
+ /**
+ * Return a new <code>InputSource</code> object that uses the
+ * <code>InputStream</code> and the system ID of the <code>Source</code>
+ * object.
+ *
+ * @throws IOException
+ * if I/O error occured.
+ */
+ private static InputSource getInputSource(final Source source) throws
IOException, SourceException {
+ final InputSource newObject = new InputSource(source.getInputStream());
+ newObject.setSystemId(source.getURI());
+ return newObject;
}
}