/* * Copyright (C) 2011 Laurent Caillette * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.novelang.outfit.xml; import java.io.IOException; import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TemplatesHandler; import javax.xml.transform.sax.TransformerHandler; import org.dom4j.Document; import org.dom4j.io.SAXWriter; import org.xml.sax.ContentHandler; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; import static com.google.common.base.Preconditions.checkNotNull; import org.novelang.outfit.loader.ResourceLoader; import org.novelang.outfit.loader.ResourceName; /** * Loads an XSL stylesheet (includes parsing) from various sources. * * @author Laurent Caillette */ public abstract class XslTransformerFactory { private final EntityResolver entityResolver ; private final URIResolver uriResolver ; private final DecoratorInstaller decoratorInstaller; /** * May be null. */ private final TransformerErrorListener transformerErrorListener; protected XslTransformerFactory( final EntityResolver entityResolver, final URIResolver uriResolver, final DecoratorInstaller decoratorInstaller, final TransformerErrorListener transformerErrorListener ) { this.transformerErrorListener = transformerErrorListener; this.entityResolver = checkNotNull( entityResolver ) ; this.uriResolver = checkNotNull( uriResolver ) ; this.decoratorInstaller = checkNotNull( decoratorInstaller ) ; } protected XslTransformerFactory( final EntityResolver entityResolver, final URIResolver uriResolver, final TransformerErrorListener transformerErrorListener ) { this.transformerErrorListener = transformerErrorListener; this.entityResolver = checkNotNull( entityResolver ) ; this.uriResolver = checkNotNull( uriResolver ) ; this.decoratorInstaller = DecoratorInstaller.NULL ; } public final TransformerHandler newTransformerHandler() throws TransformerConfigurationException, SAXException, IOException, TransformerCompositeException { final SAXTransformerFactory saxTransformerFactory = ( SAXTransformerFactory ) TransformerFactory.newInstance() ; saxTransformerFactory.setURIResolver( uriResolver ) ; if( transformerErrorListener != null ) { saxTransformerFactory.setErrorListener( transformerErrorListener ) ; } final TemplatesHandler templatesHandler = saxTransformerFactory.newTemplatesHandler() ; final XMLReader reader = XMLReaderFactory.createXMLReader() ; final ContentHandler contentHandler = decoratorInstaller.decorate(templatesHandler ) ; reader.setContentHandler( contentHandler ) ; reader.setEntityResolver( entityResolver ) ; parse( reader ) ; if( transformerErrorListener != null ) { transformerErrorListener.flush() ; } final Templates templates = templatesHandler.getTemplates() ; final TransformerHandler transformerHandler = saxTransformerFactory.newTransformerHandler( templates ) ; return transformerHandler; } protected abstract void parse( final XMLReader reader ) throws IOException, SAXException ; public static class FromInputSource extends XslTransformerFactory { private final InputSource inputSource ; public FromInputSource( final InputSource inputSource, final EntityResolver entityResolver, final URIResolver uriResolver, final DecoratorInstaller decoratorInstaller, final TransformerErrorListener transformerErrorListener ) { super( entityResolver, uriResolver, decoratorInstaller, transformerErrorListener ) ; this.inputSource = checkNotNull( inputSource ) ; } @Override protected void parse( final XMLReader reader ) throws IOException, SAXException { reader.parse( inputSource ) ; } } public static class FromResource extends FromInputSource { public FromResource( final ResourceLoader resourceLoader, final ResourceName xslFileName, final EntityResolver entityResolver, final URIResolver uriResolver, final DecoratorInstaller decoratorInstaller, final TransformerErrorListener tranformerErrorListener ) { super( new InputSource( resourceLoader.getInputStream( xslFileName ) ), entityResolver, uriResolver, decoratorInstaller, tranformerErrorListener ) ; } } public static class FromDom4jDocument extends XslTransformerFactory { private final Document document ; public FromDom4jDocument( final Document dom4jDocument, final EntityResolver entityResolver, final URIResolver uriResolver, final TransformerErrorListener transformerErrorListener ) { super( entityResolver, uriResolver, transformerErrorListener ) ; this.document = checkNotNull( dom4jDocument ) ; } @Override protected void parse( final XMLReader reader ) throws IOException, SAXException { final SAXWriter saxWriter = new SAXWriter( ) ; saxWriter.setContentHandler( reader.getContentHandler() ) ; saxWriter.write( document ) ; } } public static class FromPlayer extends XslTransformerFactory { private final SaxRecorder.Player player ; public FromPlayer( final SaxRecorder.Player player, final EntityResolver entityResolver, final URIResolver uriResolver, final TransformerErrorListener transformerErrorListener ) { super( entityResolver, uriResolver, transformerErrorListener ) ; this.player = checkNotNull( player ) ; } @Override protected void parse( final XMLReader reader ) throws IOException, SAXException { player.playOn( reader.getContentHandler() ) ; } } public interface DecoratorInstaller { ContentHandler decorate( final ContentHandler original ) ; DecoratorInstaller NULL = new DecoratorInstaller() { @Override public ContentHandler decorate( final ContentHandler original ) { return original ; } } ; } }