| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.portal.layout.renderer.aspect.impl; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.HashMap; |
| |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.sax.SAXResult; |
| import javax.xml.transform.sax.TransformerHandler; |
| |
| import org.apache.avalon.framework.activity.Disposable; |
| import org.apache.avalon.framework.parameters.ParameterException; |
| import org.apache.avalon.framework.parameters.Parameters; |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.configuration.Configurable; |
| import org.apache.cocoon.portal.PortalService; |
| import org.apache.cocoon.portal.layout.Layout; |
| import org.apache.cocoon.portal.layout.renderer.aspect.RendererAspectContext; |
| import org.apache.cocoon.sitemap.PatternException; |
| import org.apache.cocoon.xml.IncludeXMLConsumer; |
| import org.apache.cocoon.components.variables.VariableResolverFactory; |
| import org.apache.cocoon.components.variables.VariableResolver; |
| import org.apache.excalibur.source.Source; |
| import org.apache.excalibur.source.SourceResolver; |
| import org.apache.excalibur.xml.xslt.XSLTProcessor; |
| import org.apache.excalibur.xml.xslt.XSLTProcessorException; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.ext.LexicalHandler; |
| |
| /** |
| * Apply a XSLT stylesheet to the contained layout. All following renderer aspects |
| * are applied first before the XML is fed into the XSLT. All configuration and layout |
| * parameters are made available to the stylesheet. |
| * |
| * <h2>Example XML:</h2> |
| * <pre> |
| * <-- result from output of following renderers transformed by stylesheet --> |
| * </pre> |
| * |
| * |
| * The parameter values may contain Strings and/or references to input modules which will be resolved each |
| * time the aspect is rendered. |
| * <h2>Applicable to:</h2> |
| * {@link org.apache.cocoon.portal.layout.Layout} |
| * |
| * <h2>Configuration</h2> |
| * <h3>cocoon.xconf</h3> |
| * |
| * <pre> |
| * <aspect name="xslt" class="org.apache.cocoon.portal.layout.renderer.aspect.impl.XSLTAspect"> |
| * <parameters> |
| * <parameter name="<i>name1</i>" value="<i>parameter value</i>"/> |
| * <parameter name="<i>name2</i>" value="<i>parameter value</i>"/> |
| * <parameter> |
| * </aspect> |
| * </pre> |
| * |
| * <h2>Parameters</h2> |
| * <table><tbody> |
| * <tr><th>style</th><td></td><td>req</td><td>String</td><td><code>null</code></td></tr> |
| * <tr><th>xslt-processor-role</th><td></td><td>req</td><td>String</td><td><code>null</code></td></tr> |
| * </tbody></table> |
| * |
| * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a> |
| * @author <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a> |
| * |
| * @version CVS $Id$ |
| */ |
| public class XSLTAspect |
| extends AbstractAspect |
| implements Disposable, Configurable { |
| |
| protected List variables = new ArrayList(); |
| |
| protected Parameters parameters; |
| |
| protected VariableResolverFactory variableFactory; |
| |
| /* (non-Javadoc) |
| * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) |
| */ |
| public void service(ServiceManager manager) throws ServiceException { |
| super.service(manager); |
| this.variableFactory = (VariableResolverFactory) this.manager.lookup(VariableResolverFactory.ROLE); |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) |
| */ |
| public void configure(Configuration config) throws ConfigurationException { |
| Configuration parameterItems = config.getChild("parameters", false); |
| |
| if (parameterItems != null) { |
| this.parameters = Parameters.fromConfiguration(parameterItems); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.cocoon.portal.layout.renderer.RendererAspect#toSAX(org.apache.cocoon.portal.layout.renderer.RendererAspectContext, org.apache.cocoon.portal.layout.Layout, org.apache.cocoon.portal.PortalService, org.xml.sax.ContentHandler) |
| */ |
| public void toSAX(RendererAspectContext context, |
| Layout layout, |
| PortalService service, |
| ContentHandler handler) |
| throws SAXException { |
| PreparedConfiguration config = (PreparedConfiguration)context.getAspectConfiguration(); |
| |
| XSLTProcessor processor = null; |
| Source stylesheet = null; |
| SourceResolver resolver = null; |
| try { |
| resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE); |
| stylesheet = resolver.resolveURI(this.getStylesheetURI(config, layout)); |
| processor = (XSLTProcessor) this.manager.lookup(config.xsltRole); |
| TransformerHandler transformer = processor.getTransformerHandler(stylesheet); |
| // Pass configured parameters to the stylesheet. |
| if (config.parameters.size() > 0) { |
| Map.Entry entry; |
| Transformer theTransformer = transformer.getTransformer(); |
| Iterator iter = config.parameters.entrySet().iterator(); |
| while (iter.hasNext()) { |
| entry = (Map.Entry) iter.next(); |
| String value = getParameterValue(entry); |
| theTransformer.setParameter((String) entry.getKey(), value); |
| } |
| } |
| |
| Map parameter = layout.getParameters(); |
| if (parameter.size() > 0) { |
| Map.Entry entry; |
| Transformer theTransformer = transformer.getTransformer(); |
| for (Iterator iter = parameter.entrySet().iterator(); iter.hasNext();) { |
| entry = (Map.Entry) iter.next(); |
| theTransformer.setParameter((String)entry.getKey(), entry.getValue()); |
| } |
| } |
| SAXResult result = new SAXResult(new IncludeXMLConsumer((handler))); |
| if (handler instanceof LexicalHandler) { |
| result.setLexicalHandler((LexicalHandler) handler); |
| } |
| transformer.setResult(result); |
| transformer.startDocument(); |
| context.invokeNext(layout, service, transformer); |
| |
| transformer.endDocument(); |
| } catch (XSLTProcessorException xpe) { |
| throw new SAXException("XSLT Exception.", xpe); |
| } catch (IOException io) { |
| throw new SAXException("Error in resolving.", io); |
| } catch (ServiceException ce) { |
| throw new SAXException("Unable to lookup component.", ce); |
| } finally { |
| if (null != resolver) { |
| resolver.release(stylesheet); |
| this.manager.release(resolver); |
| } |
| this.manager.release(processor); |
| } |
| } |
| |
| protected String getStylesheetURI(PreparedConfiguration config, Layout layout) |
| throws SAXException { |
| // FIXME Get the stylesheet either from a layout attribute or another aspect |
| try { |
| String stylesheet = config.stylesheet.resolve(); |
| return stylesheet; |
| } catch (PatternException pe) { |
| throw new SAXException("Pattern exception during variable resolving.", pe); |
| } |
| } |
| |
| protected String getParameterValue(Map.Entry entry) throws SAXException { |
| try { |
| return ((VariableResolver)entry.getValue()).resolve(); |
| } catch (PatternException pe) { |
| throw new SAXException("Unable to get value for parameter " + entry.getKey(), pe); |
| } |
| } |
| |
| |
| protected static class PreparedConfiguration { |
| public VariableResolver stylesheet; |
| public String xsltRole; |
| public Map parameters = new HashMap(); |
| |
| public void takeValues(PreparedConfiguration from) { |
| this.stylesheet = from.stylesheet; |
| this.xsltRole = from.xsltRole; |
| this.parameters = from.parameters; |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.cocoon.portal.layout.renderer.aspect.RendererAspect#prepareConfiguration(org.apache.avalon.framework.parameters.Parameters) |
| */ |
| public Object prepareConfiguration(Parameters configuration) |
| throws ParameterException { |
| PreparedConfiguration pc = new PreparedConfiguration(); |
| pc.xsltRole = configuration.getParameter("xslt-processor-role", XSLTProcessor.ROLE); |
| String stylesheet = configuration.getParameter("style"); |
| try { |
| pc.stylesheet = this.variableFactory.lookup( stylesheet ); |
| } catch (PatternException pe) { |
| throw new ParameterException("Unknown pattern for stylesheet " + stylesheet, pe); |
| } |
| this.variables.add(pc.stylesheet); |
| if (this.parameters != null) { |
| String[] name = this.parameters.getNames(); |
| for (int i=0; i < name.length; ++i) { |
| try { |
| VariableResolver resolver = |
| this.variableFactory.lookup(this.parameters.getParameter(name[i])); |
| this.variables.add(resolver); |
| pc.parameters.put(name[i], resolver); |
| } catch (PatternException e) { |
| throw new ParameterException("Invalid value for parameter " + name[i], e); |
| } |
| } |
| } |
| return pc; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.avalon.framework.activity.Disposable#dispose() |
| */ |
| public void dispose() { |
| if ( this.manager != null ) { |
| Iterator vars = this.variables.iterator(); |
| while ( vars.hasNext() ) { |
| this.variableFactory.release( (VariableResolver) vars.next() ); |
| } |
| this.variables.clear(); |
| this.manager.release( this.variableFactory); |
| this.manager = null; |
| this.variableFactory = null; |
| } |
| } |
| } |