Index: src/docbook/other/pass/UCS2.xml
===================================================================
--- src/docbook/other/pass/UCS2.xml (revision 4465)
+++ src/docbook/other/pass/UCS2.xml (working copy)
@@ -1,6 +1,4 @@
-
+ * Specifies a list of customization stylesheets for the specified output + * formats. The default value is to use no customizations, but you can point + * this configuration parameter to your own stylesheets that set parameters + * or override templates. + *
+ *+ * An example configuration that changes the pdf stylesheet: + *
+ * + *+ * <customizations> + * <pdf>src/main/resources/docbook2pdf.xsl</pdf> + * </customizations> + *+ * + *
+ * All relative URLs are resolved against resourcePath + *
+ * + * @parameter + */ + private Map customizations = new HashMap(); + + /** + *+ * Specifies a list of transformation profiles, e.g. + *
+ * + *+ * <profiles> + * <transformProfile> + * <id>linux</id> + * <os>linux</os> + * </transformProfile> + * <transformProfile> + * <id>windows</id> + * <os>windows</os> + * </transformProfile> + * <transformProfile> + * <id>nonlinux</id> + * <operatingsystems> + * <os>windows</os> + * <os>macosx</os> + * </operatingsystems> + * </transformProfile> + * </profiles> + *+ * + *
+ * This examples creates three profiles: one containing only content marked + * for linux, one containing only content marked for windows and a third + * with content marked for either windows or mac os x. The id element is + * required for each profile, as the resulting files will have the pattern + * $filename.$profile.$ext. You can combine profile conditions e.g. having + * an os element and an arch element in place and you can profile for + * multiple values as shown in the nonlinux profile. + *
+ *+ * All available filtering elements are: + *
+ *+ * Additionally there is support for attribute-based filtering, which + * requires the use of attribute and value elements. For more information + * about DocBook profiling, see Chapter 25. + * Profiling (conditional text) in Bob Stayton's DocBook XSL: The + * Complete Guide. + *
+ * + * @parameter + */ + private TransformProfile[] profiles = new TransformProfile[] {}; + + /** + * Specifies the stylesheet location, useful if you want to use a local copy + * or a specific version instead of the current release from the maven + * repository. + * + * The path pattern is resource://<groupId>/<artifactId<>/<pathinjar> + * + * @parameter expression="${stylesheetLocation}" + * default-value="resource://docbook/docbook-xsl/docbook-xsl-1.67.2/" + */ private String stylesheetLocation; /** @@ -100,6 +213,11 @@ * @readonly */ private Settings settings; + + /** + * @parameter expression="${plugin.artifacts}" + */ + private Collection artifacts; public void execute() throws MojoExecutionException, MojoFailureException @@ -118,7 +236,14 @@ System.setProperty( "http.proxyPort", new Integer( activeProxy.getPort() ).toString() ); System.setProperty( "http.nonProxyHosts", activeProxy.getNonProxyHosts() ); } - + + // Set XInclude Xerces parser so we're able to process master olink database file + String xercesParser = System.getProperty( TransformMojo.XERCES_PARSER_CONFIG ); + System.setProperty( TransformMojo.XERCES_PARSER_CONFIG, TransformMojo.XERCES_XINCLUDE_PARSER ); + String entityResolver = System.getProperty( TransformMojo.XERCES_RESOLVER_CONFIG ); + System.setProperty( TransformMojo.XERCES_RESOLVER_CONFIG, TransformMojo.DOCBOOK_MOJO_RESOVER ); + + URI stylesheetLocationURI; try { @@ -131,25 +256,58 @@ try { - OLinkDBUpdater olinkDBUpdater = new OLinkDBUpdater( log, this.sourceDirectory, this.databaseDirectory, - stylesheetLocationURI ); - olinkDBUpdater.update(); + if ( this.sourceDirectory.exists() ) + { - DocumentTransformer documentTransformer = new DocumentTransformer( log, this.sourceDirectory, - this.resourceDirectory, - this.databaseDirectory, - this.outputDirectory, - stylesheetLocationURI ); - documentTransformer.transform(); + OLinkDBUpdater olinkDBUpdater = new OLinkDBUpdater( log, this.sourceDirectory, this.databaseDirectory, + stylesheetLocationURI, this.artifacts ); + olinkDBUpdater.update(); + + DocumentTransformer documentTransformer = new DocumentTransformer( log, this.sourceDirectory, + this.resourceDirectory, + this.databaseDirectory, + this.outputDirectory, + stylesheetLocationURI, + this.customizations, + this.artifacts); + for ( int i = 0; i < outputFormats.length; i++ ) + { + documentTransformer.enableOutputFormat( outputFormats[i] ); + } + + documentTransformer.transform(); + + if ( this.profiles.length != 0 ) + { + for ( int i = 0; i < profiles.length; i++ ) + { + documentTransformer.transform( this.profiles[i] ); + } + } + } } finally { - resetProperties( httpProxyHost, httpProxyPort, httpNonProxyHosts ); + resetProperties( xercesParser, httpProxyHost, httpProxyPort, httpNonProxyHosts, entityResolver ); } } - private void resetProperties( String httpProxyHost, String httpProxyPort, String httpNonProxyHosts ) + private void resetProperties( String xercesParser, String httpProxyHost, String httpProxyPort, + String httpNonProxyHosts, String entityResolver ) { + // Reset XInclude Xerces parser to previous value + if ( xercesParser != null ) + { + System.setProperty( TransformMojo.XERCES_PARSER_CONFIG, xercesParser ); + System.setProperty( TransformMojo.XERCES_RESOLVER_CONFIG, entityResolver ); + } + else + { + // In 1.4 there's no clear property method... is this correct? + System.setProperty( TransformMojo.XERCES_PARSER_CONFIG, "" ); + System.setProperty( TransformMojo.XERCES_RESOLVER_CONFIG, "" ); + } + if ( httpProxyHost != null ) { System.setProperty( "http.proxyHost", httpProxyHost ); Index: src/main/java/org/codehaus/mojo/docbook/DocumentTransformer.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/DocumentTransformer.java (revision 4465) +++ src/main/java/org/codehaus/mojo/docbook/DocumentTransformer.java (working copy) @@ -1,6 +1,6 @@ -/* +/* * maven-docbook-plugin - Copyright (C) 2005 OPEN input - http://www.openinput.com/ - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@ -23,34 +23,51 @@ */ package org.codehaus.mojo.docbook; +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.net.URI; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.Fop; +import org.apache.fop.apps.FopFactory; +import org.apache.fop.apps.MimeConstants; import org.apache.maven.plugin.logging.Log; import org.codehaus.plexus.compiler.util.scan.InclusionScanException; import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner; import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.FileUtils; - /** + * A helper class for transforming DocBook documents into different output + * formats. + * * @author jgonzalez + * @author Lars Trieloff */ public class DocumentTransformer { + private Set sourcePatterns; + protected Log log; protected File sourceDirectory; @@ -63,13 +80,25 @@ protected URI stylesheetLocation; + private boolean generateHtml; + + private boolean generatePdf; + + private MojoURIResolver mojoResolver; + + private String xslfoCustomization; + + private String xhtmlCustomization; + /** * @param log * @param sourceDirectory * @param outputDirectory + * @param customizations + * @param artifacts */ public DocumentTransformer( Log log, File sourceDirectory, File resourceDirectory, File databaseDirectory, - File outputDirectory, URI stylesheetLocation ) + File outputDirectory, URI stylesheetLocation, Map customizations, Collection artifacts ) { this.log = log; this.sourceDirectory = sourceDirectory; @@ -77,13 +106,36 @@ this.databaseDirectory = databaseDirectory; this.outputDirectory = outputDirectory; this.stylesheetLocation = stylesheetLocation; + this.mojoResolver = new MojoURIResolver(artifacts); + + this.xslfoCustomization = (String) customizations.get( "pdf" ); + this.xhtmlCustomization = (String) customizations.get( "xhtml" ); + + this.sourcePatterns = new HashSet( 2 ); + this.sourcePatterns.add( "*.xml" ); + this.sourcePatterns.add( "**/*xml" ); } public void transform() { - StaleSourceScanner scanner = new StaleSourceScanner( 0, Collections.singleton( "**/*.xml" ), - Collections.EMPTY_SET ); - scanner.addSourceMapping( new SuffixMapping( ".xml", ".html" ) ); + this.transform( null ); + } + + /** + * @param transformProfile + */ + public void transform( TransformProfile transformProfile ) + { + StaleSourceScanner scanner = new StaleSourceScanner( 0, this.sourcePatterns, Collections.EMPTY_SET ); + String profile = getFileExtension( transformProfile ); + if ( generateHtml ) + { + scanner.addSourceMapping( new SuffixMapping( ".xml", profile + "html" ) ); + } + if ( generatePdf ) + { + scanner.addSourceMapping( new SuffixMapping( ".xml", profile + "pdf" ) ); + } Set staleDocbookFiles; try { @@ -99,12 +151,12 @@ DirectoryScanner docbookScanner = new DirectoryScanner(); docbookScanner.setBasedir( this.sourceDirectory ); docbookScanner.setFollowSymlinks( true ); - docbookScanner.setIncludes( new String[] { "**/*.xml" } ); + docbookScanner.setIncludes( new String[] { "**/*.xml", "*.xml" } ); docbookScanner.scan(); String[] docbookFiles = docbookScanner.getIncludedFiles(); this.prepareFileSystem( docbookFiles ); - this.transformDocuments( staleDocbookFiles ); + this.transformDocuments( staleDocbookFiles, transformProfile ); } else { @@ -130,6 +182,17 @@ } } + private String getFileExtension( TransformProfile transformProfile ) + { + StringBuffer profile = new StringBuffer( "." ); + if ( transformProfile != null ) + { + profile.append( transformProfile.getId() ); + profile.append( "." ); + } + return profile.toString(); + } + /** * @param docbookFiles */ @@ -137,6 +200,7 @@ { this.log.debug( "Creating output directories for the following files - " + Arrays.asList( docbookFiles ).toString() ); + this.outputDirectory.mkdirs(); // TODO: This should be a bit smarter also, shouldn't it? for ( int fileIndex = 0; fileIndex < docbookFiles.length; fileIndex++ ) { @@ -150,56 +214,249 @@ } } - protected void transformDocuments( Set docbookFiles ) + protected void transformDocuments( Set docbookFiles, TransformProfile transformProfile ) { this.log.info( "Transforming " + docbookFiles.size() + " Docbook stale file(s)" ); - Source docbookStyleSheetSource = new StreamSource( this.stylesheetLocation.resolve( "xhtml/docbook.xsl" ) - .toString() ); + Transformer xhtmlTransformer = null; + Transformer xslfoTransformer = null; + FopFactory fopFactory = null; + URI olinkDBURI = new File( this.databaseDirectory + File.separator + "olinkdb.xml" ).toURI(); - Transformer documentTransformer; + if ( generateHtml ) + { + xhtmlTransformer = createXHTMLTransformer( olinkDBURI, transformProfile ); + } + if ( generatePdf ) + { + xslfoTransformer = createXSLFOTransformer( olinkDBURI, transformProfile ); + fopFactory = FopFactory.newInstance(); + fopFactory.setURIResolver( this.mojoResolver ); + } + Iterator filesIterator = docbookFiles.iterator(); + while ( filesIterator.hasNext() ) + { + File docbookFile = (File) filesIterator.next(); + if ( generateHtml ) + { + transformXhtml( xhtmlTransformer, docbookFile, transformProfile ); + } + if ( generatePdf ) + { + transformPdf( xslfoTransformer, docbookFile, fopFactory, transformProfile ); + } + } + } + + private Transformer createXSLFOTransformer( URI olinkDBURI, TransformProfile transformProfile ) + { + Transformer xslfoTransformer; + TransformerFactory xslfoTf = TransformerFactory.newInstance(); + xslfoTf.setURIResolver( this.mojoResolver ); + Source docbookStyleSheetSource; + String location = this.stylesheetLocation.toASCIIString() + "fo/"; + String xslt = null; + + if ( ( this.xslfoCustomization == null ) && ( transformProfile == null ) ) + { + xslt = "docbook.xsl"; + } + else if ( ( this.xslfoCustomization == null ) && ( transformProfile != null ) ) + { + xslt = "profile-docbook.xsl"; + } + else + { + location = this.sourceDirectory.toURI().toString(); + xslt = this.xslfoCustomization; + } + + try + { + docbookStyleSheetSource = this.mojoResolver.resolve( xslt, location ); + } + catch ( TransformerException e ) + { + throw new RuntimeException( "Unable to resolve " + location + "/" + xslt, e); + } + + try + { + xslfoTransformer = xslfoTf.newTransformer( docbookStyleSheetSource ); + } + catch ( TransformerConfigurationException e ) + { + throw new RuntimeException( "Unable to create new instance of transformer from source " + + docbookStyleSheetSource.getSystemId() ); + } + xslfoTransformer.setParameter( "target.database.document", olinkDBURI.toString() ); + + if ( transformProfile != null ) + { + transformProfile.setParameters( xslfoTransformer ); + } + + this.log.debug( "XSL:FO Style sheet loaded." ); + return xslfoTransformer; + } + + private Transformer createXHTMLTransformer( URI olinkDBURI, TransformProfile transformProfile ) + { + Transformer xhtmlTransformer; + TransformerFactory xhtmlTf = TransformerFactory.newInstance(); + xhtmlTf.setURIResolver( this.mojoResolver ); + Source docbookStyleSheetSource; + String location = this.stylesheetLocation.toASCIIString() + "xhtml/"; + String xslt = null; + + if ( ( this.xslfoCustomization == null ) && ( transformProfile == null ) ) + { + xslt = "docbook.xsl"; + } + else if ( ( this.xslfoCustomization == null ) && ( transformProfile != null ) ) + { + xslt = "profile-docbook.xsl"; + } + else + { + location = this.sourceDirectory.toURI().toString(); + xslt = this.xhtmlCustomization; + } + + try + { + docbookStyleSheetSource = this.mojoResolver.resolve( xslt, location ); + } + catch ( TransformerException e ) + { + throw new RuntimeException( "Unable to resolve " + location + "/" + xslt, e); + } + + try + { + xhtmlTransformer = xhtmlTf.newTransformer( docbookStyleSheetSource ); + } + catch ( TransformerConfigurationException e ) + { + throw new RuntimeException( "Unable to create new instance of transformer from source " + + docbookStyleSheetSource.getSystemId() ); + } + xhtmlTransformer.setParameter( "target.database.document", olinkDBURI.toString() ); + xhtmlTransformer.setParameter( "generate.toc", "" ); + + if ( transformProfile != null ) + { + transformProfile.setParameters( xhtmlTransformer ); + } + + this.log.debug( "XHTML Style sheet loaded." ); + return xhtmlTransformer; + } + + private void transformXhtml( Transformer documentTransformer, File docbookFile, TransformProfile transformProfile ) + { + this.log.debug( "Processing " + this.sourceDirectory + File.separator + docbookFile ); + + Source source; + try + { + source = this.mojoResolver.resolve( docbookFile.toURI().toString(), null ); + } + catch ( TransformerException e ) + { + throw new RuntimeException( "Unable to resolve " + docbookFile.toURI().toString(), e); + } + + String relativePath = docbookFile.getAbsolutePath().substring( + (int) this.sourceDirectory.getAbsolutePath() + .length() ); + + File resultFile = new File( this.outputDirectory, relativePath.substring( 0, relativePath.lastIndexOf( '.' ) ) + + getFileExtension( transformProfile ) + "html" ); + Result result = new StreamResult( resultFile.getAbsolutePath() ); + + documentTransformer.setParameter( "current.docid", OLinkDBUpdater.computeFileID( relativePath ) ); + // TODO: Parametrize this !!!! + documentTransformer + .setParameter( "html.stylesheet", this.pathToResources( relativePath ) + "css/xhtml.css" ); + try { - documentTransformer = TransformerFactory.newInstance().newTransformer( docbookStyleSheetSource ); + documentTransformer.transform( source, result ); } catch ( TransformerException e ) { - throw new RuntimeException( "Unable to get a transformer instance from source " + docbookStyleSheetSource.getSystemId(), e ); + throw new RuntimeException( "Unable to transform from source " + source.getSystemId() + " into " + result.getSystemId(), e ); } - URI olinkDBURI = new File( this.databaseDirectory + File.separator + "olinkdb.xml" ).toURI(); - documentTransformer.setParameter( "target.database.document", olinkDBURI.toString() ); - documentTransformer.setParameter( "generate.toc", "" ); - this.log.debug( "Style sheet loaded." ); + this.log.debug( "Generated " + this.databaseDirectory + File.separator + docbookFile ); + } - Iterator filesIterator = docbookFiles.iterator(); - while ( filesIterator.hasNext() ) + private void transformPdf( Transformer documentTransformer, File docbookFile, FopFactory fopFactory, + TransformProfile transformProfile ) + { + this.log.debug( "Processing " + this.sourceDirectory + File.separator + docbookFile ); + + Source source; + try { - File docbookFile = (File) filesIterator.next(); - this.log.debug( "Processing " + docbookFile ); - Source source = new StreamSource( docbookFile ); - String relativePath = docbookFile.getAbsolutePath().substring( - (int) this.sourceDirectory.getAbsolutePath() - .length() ); - File resultFile = new File( this.outputDirectory, relativePath - .substring( 0, relativePath.lastIndexOf( '.' ) ) - + ".html" ); - Result result = new StreamResult( resultFile.getAbsolutePath() ); + source = this.mojoResolver.resolve( docbookFile.toURI().toString(), null ); + } + catch ( TransformerException e ) + { + throw new RuntimeException( "Unable to resolve " + docbookFile.toURI().toString(), e); + } - documentTransformer.setParameter( "current.docid", OLinkDBUpdater.computeFileID( relativePath ) ); - // TODO: Parametrize this !!!! - documentTransformer - .setParameter( "html.stylesheet", this.pathToResources( relativePath ) + "css/xhtml.css" ); + String relativePath = docbookFile.getAbsolutePath().substring( + (int) this.sourceDirectory.getAbsolutePath() + .length() ); + File resultFile = new File( this.outputDirectory, relativePath.substring( 0, relativePath.lastIndexOf( '.' ) ) + + getFileExtension( transformProfile ) + "pdf" ); + this.mojoResolver.setDocumentUri( docbookFile.toURI() ); + documentTransformer.setParameter( "current.docid", OLinkDBUpdater.computeFileID( relativePath ) ); - try { - documentTransformer.transform( source, result ); + OutputStream out; + try + { + out = new BufferedOutputStream( new FileOutputStream( resultFile.getAbsolutePath() ) ); + } + catch ( FileNotFoundException e ) + { + throw new RuntimeException( "File not found " + resultFile.getAbsolutePath(), e ); + } + + Result intermediate; + try + { + Fop fop = fopFactory.newFop( MimeConstants.MIME_PDF, out ); + intermediate = new SAXResult( fop.getDefaultHandler() ); + } + catch ( FOPException e ) + { + throw new RuntimeException( "Unable to create FOP instance", e); + } + + try + { + documentTransformer.transform( source, intermediate ); + } + catch ( TransformerException e ) + { + throw new RuntimeException( "Unable to transform from source " + source.getSystemId() + " into " + + intermediate.getSystemId(), e ); + } + finally + { + try + { + out.close(); } - catch ( TransformerException e ) + catch ( IOException e ) { - throw new RuntimeException( "Unable to transform from source " + source.getSystemId() + " into " + result.getSystemId(), e ); + //ignore } - - this.log.debug( "Generated " + this.databaseDirectory + File.separator + docbookFile ); } + this.log.debug( "Generated " + this.databaseDirectory + File.separator + docbookFile ); } + protected String pathToResources( String relativePath ) { @@ -212,4 +469,24 @@ } return pathToResources.toString(); } + + /** + * Enables a specified output format. + * + * @param format + * the format + */ + public void enableOutputFormat( String format ) + { + if ( "xhtml".equalsIgnoreCase( format ) ) + { + generateHtml = true; + } + if ( "pdf".equalsIgnoreCase( format ) ) + { + generatePdf = true; + } + + } + } Index: src/main/java/org/codehaus/mojo/docbook/MojoURIResolver.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/MojoURIResolver.java (revision 0) +++ src/main/java/org/codehaus/mojo/docbook/MojoURIResolver.java (revision 0) @@ -0,0 +1,213 @@ +/* + * maven-docbook-plugin - Copyright (C) 2006 Mindquarry GmbH - http://www.mindquarry.com/ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: $ + */ +package org.codehaus.mojo.docbook; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; + +import org.apache.maven.artifact.Artifact; +import org.apache.xml.resolver.tools.CatalogResolver; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; + +import com.sun.org.apache.xerces.internal.util.URI.MalformedURIException; + +public class MojoURIResolver + extends CatalogResolver + implements URIResolver, EntityResolver +{ + private Collection artifacts; + + private URI documentUri = null; + + public MojoURIResolver(Collection artifacts) { + this.artifacts = artifacts; + } + + public InputSource resolveEntity( final String href, final String base ) + { + InputSource result; + String fullUri = makeFullUri( href, base ); + if ( fullUri.startsWith( "resource://" ) ) + { + try + { + result = new InputSource( getResourceAsStream( fullUri ) ); + } + catch ( IOException ioe ) + { + result = null; + } + + } + else + { + result = super.resolveEntity( href, base ); + } + if ( result == null ) + { + result = new InputSource( fullUri ); + } + result.setSystemId( fullUri ); + return result; + } + + public Source resolve( final String href, final String base ) + throws TransformerException + { + Source result; + String fullUri = makeFullUri( href, base ); + try + { + try + { + XMLReader reader; + // get a SAXParserFactory instance + SAXParserFactory SAXpf = SAXParserFactory.newInstance(); + // enabling the namespaces processing + SAXpf.setNamespaceAware( true ); + // get a SAXParser object + SAXParser SAXparser = SAXpf.newSAXParser(); + // get the XMLReader + reader = SAXparser.getXMLReader(); + reader.setEntityResolver( this ); + // creating the SAXSource + InputSource insrc = this.resolveEntity( href, base ); + result = new SAXSource( reader, insrc ); + } + catch ( javax.xml.parsers.ParserConfigurationException e ) + { + result = new StreamSource( getResourceAsStream( fullUri ) ); + } + catch ( org.xml.sax.SAXException e ) + { + result = new StreamSource( getResourceAsStream( fullUri ) ); + } + result.setSystemId( fullUri ); + return result; + } catch ( IOException ioe ) + { + throw new TransformerException( "unable to load resource " + fullUri , ioe ); + } + } + + private InputStream getResourceAsStream( String fullUri ) throws IOException + { + try + { + URI uri = new URI(fullUri); + + String groupId = uri.getAuthority(); + String path = uri.getPath().substring( 1 ); + String artifactId = path.substring( 0, path.indexOf( "/" ) ); + String resource = path.substring(path.indexOf("/")); + + for ( Iterator i = this.artifacts.iterator() ; i.hasNext() ; ) + { + Artifact a = (Artifact) i.next(); + if ( ( a.getGroupId().equals( groupId ) ) + && ( a.getArtifactId().equals( artifactId ) ) ) + { + ZipFile jar = new ZipFile(a.getFile()); + for ( Enumeration e = jar.entries(); e.hasMoreElements(); ) + { + ZipEntry je = (ZipEntry) e.nextElement(); + String name = je.getName(); + if ( !name.startsWith("/") ) + { + name = "/" + name; + } + if ( name.equals(resource) ) { + return jar.getInputStream(je); + } + } + } + } + + return MojoURIResolver.class.getResourceAsStream( fullUri.substring( 10 ) ); + } catch (URISyntaxException use) + { + throw new IOException(use.getLocalizedMessage()); + } + } + + private String makeFullUri( final String href, final String base ) + { + String fullUri = href; + //if it is no absolute url starting with scheme:/ + if ( ( href != null ) && ( base != null ) ) + { + try + { + fullUri = URI.create( base ).resolve( href ).toString(); + } + catch ( IllegalArgumentException use ) + { + fullUri = base; + } + } + else if ( ( href != null ) && ( href.indexOf( ":/" ) != -1 ) ) + { + fullUri = href; + } + else if ( base != null ) + { + fullUri = base; + } + else if ( this.documentUri != null ) + { + fullUri = documentUri.resolve( href ).toString(); + } + else + { + fullUri = href; + } + return fullUri; + } + + public void setDocumentUri( URI documentUri ) + { + this.documentUri = documentUri; + } + +} Index: src/main/java/org/codehaus/mojo/docbook/OLinkDBUpdater.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/OLinkDBUpdater.java (revision 4465) +++ src/main/java/org/codehaus/mojo/docbook/OLinkDBUpdater.java (working copy) @@ -30,6 +30,7 @@ import java.io.Writer; import java.net.URI; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; @@ -39,8 +40,11 @@ import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; @@ -62,18 +66,22 @@ protected File databaseDirectory; protected URI stylesheetLocation; + + protected Collection artifacts; /** * @param log * @param sourceDirectory * @param databaseDirectory + * @param collection */ - public OLinkDBUpdater( Log log, File sourceDirectory, File databaseDirectory, URI stylesheetLocation ) + public OLinkDBUpdater( Log log, File sourceDirectory, File databaseDirectory, URI stylesheetLocation, Collection artifacts ) { this.log = log; this.sourceDirectory = sourceDirectory; this.databaseDirectory = databaseDirectory; this.stylesheetLocation = stylesheetLocation; + this.artifacts = artifacts; } public void update() @@ -137,18 +145,36 @@ protected void updateOLinkDatabase( Set docbookFiles ) { this.log.info( "Loading olink database generation stylesheet" ); - Source docbookStyleSheetSource = new StreamSource( this.stylesheetLocation.resolve( "xhtml/docbook.xsl" ) - .toString() ); - Transformer olinkDBGenerator; + TransformerFactory tf = TransformerFactory.newInstance(); + MojoURIResolver resolver = new MojoURIResolver(artifacts); + String styleSheetSourceLocation = this.stylesheetLocation.toASCIIString() + "xhtml/"; + + Source docbookStyleSheetSource; try { - TransformerFactory factory = TransformerFactory.newInstance(); - olinkDBGenerator = factory.newTransformer( docbookStyleSheetSource ); + docbookStyleSheetSource = resolver.resolve( "docbook.xsl", styleSheetSourceLocation ); } catch ( TransformerException e ) { + throw new RuntimeException( "Unable to resolve " + styleSheetSourceLocation + "/docbook.xsl", e ); + } + + tf.setURIResolver( resolver ); + if ( tf.getFeature( SAXSource.FEATURE ) ) + { + SAXTransformerFactory stf = ( (SAXTransformerFactory) tf ); + } + + Transformer olinkDBGenerator; + try + { + olinkDBGenerator = tf.newTransformer( docbookStyleSheetSource ); + } + catch ( TransformerConfigurationException e ) + { throw new RuntimeException( "Unable to get a transformer instance from source " + docbookStyleSheetSource.getSystemId(), e ); } + olinkDBGenerator.setParameter( "collect.xref.targets", "only" ); olinkDBGenerator.setParameter( "generate.toc", "" ); @@ -167,7 +193,6 @@ Result result = new StreamResult( new OLinkDBUpdater.NullWriter() ); olinkDBGenerator.setParameter( "targets.filename", databaseFile.getAbsolutePath() ); - try { olinkDBGenerator.transform( source, result ); @@ -176,7 +201,6 @@ { throw new RuntimeException( "Unable to transform from source " + source.getSystemId() + " into " + result.getSystemId(), e ); } - this.log.debug( "Generated " + this.databaseDirectory + File.separator + docbookFile ); } } @@ -190,7 +214,7 @@ this.log.info( "Creating master olink database file " + file ); try { - BufferedWriter masterOlinkDBFile = new BufferedWriter( new FileWriter( file )); + BufferedWriter masterOlinkDBFile = new BufferedWriter( new FileWriter( file ) ); // Write header masterOlinkDBFile.write( "" ); Index: src/main/java/org/codehaus/mojo/docbook/TransformProfile.java =================================================================== --- src/main/java/org/codehaus/mojo/docbook/TransformProfile.java (revision 0) +++ src/main/java/org/codehaus/mojo/docbook/TransformProfile.java (revision 0) @@ -0,0 +1,411 @@ +/* + * maven-docbook-plugin - Copyright (C) 2006 Mindquarry GmbH - http://www.mindquarry.com/ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: $ + */ +package org.codehaus.mojo.docbook; + +import javax.xml.transform.Transformer; + +/** + * A holder of profiling information, like operating system, architecture or + * vendor. + * + * @author Lars Trieloff + */ +public class TransformProfile { + /** + * A unique id for the profile + */ + private String id; + + /** + * The attribute to profile for (attribute-based profiling) + */ + private String attribute; + /** + * The attribute's value to profile for (for attribute-based profiling) + */ + private String value; + + /** + * For profiling for a single hardware architecture + */ + private String arch; + /** + * For profiling for multiple hardware architectures + */ + private String[] archictectures; + /** + * For profiling for a single condition + */ + private String condition; + /** + * For profiling for multiple conditions + */ + private String[] conditions; + /** + * For profiling for a single conformance + */ + private String conformance; + /** + * For profiling for multiple conformances + */ + private String[] conformances; + /** + * For profiling for a single language + */ + private String lang; + /** + * For profiling for multiple languages + */ + private String[] languages; + /** + * For profiling for a single operating system + */ + private String os; + /** + * For profiling for multiple operating systems + */ + private String[] operatingsystems; + /** + * For profiling for a single revision + */ + private String revision; + /** + * For profiling for multiple revisions + */ + private String[] revisions; + /** + * For profiling for a single role + */ + private String role; + /** + * For profiling for multiple roles + */ + private String[] roles; + /** + * For profiling for a single security level + */ + private String security; + /** + * For profiling for multiple profiling levels + */ + private String[] securities; + /** + * For profiling for a single user level + */ + private String userlevel; + /** + * For profiling for multiple user levels + */ + private String[] userlevels; + /** + * For profiling for a single vendor + */ + private String vendor; + /** + * For profiling for multiple vendors + */ + private String vendors[]; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getArch() { + return arch; + } + + public void setArch(String arch) { + this.arch = arch; + } + + public String[] getArchictectures() { + return archictectures; + } + + public void setArchictectures(String[] archictectures) { + this.archictectures = archictectures; + } + + public String getCondition() { + return condition; + } + + public void setCondition(String condition) { + this.condition = condition; + } + + public String[] getConditions() { + return conditions; + } + + public void setConditions(String[] conditions) { + this.conditions = conditions; + } + + public String getConformance() { + return conformance; + } + + public void setConformance(String conformance) { + this.conformance = conformance; + } + + public String[] getConformances() { + return conformances; + } + + public void setConformances(String[] conformances) { + this.conformances = conformances; + } + + public String getLang() { + return lang; + } + + public void setLang(String lang) { + this.lang = lang; + } + + public String[] getLanguages() { + return languages; + } + + public void setLanguages(String[] languages) { + this.languages = languages; + } + + public String getOs() { + return os; + } + + public void setOs(String os) { + this.os = os; + } + + public String[] getOperatingsystems() { + return operatingsystems; + } + + public void setOperatingsystems(String[] operatingsystems) { + this.operatingsystems = operatingsystems; + } + + public String getRevision() { + return revision; + } + + public void setRevision(String revision) { + this.revision = revision; + } + + public String[] getRevisions() { + return revisions; + } + + public void setRevisions(String[] revisions) { + this.revisions = revisions; + } + + public String getRole() { + return role; + } + + public void setRole(String role) { + this.role = role; + } + + public String[] getRoles() { + return roles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public String getSecurity() { + return security; + } + + public void setSecurity(String security) { + this.security = security; + } + + public String[] getSecurities() { + return securities; + } + + public void setSecurities(String[] securities) { + this.securities = securities; + } + + public String getUserlevel() { + return userlevel; + } + + public void setUserlevel(String userlevel) { + this.userlevel = userlevel; + } + + public String[] getUserlevels() { + return userlevels; + } + + public void setUserlevels(String[] userlevels) { + this.userlevels = userlevels; + } + + public String getVendor() { + return vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public String[] getVendors() { + return vendors; + } + + public void setVendors(String[] vendors) { + this.vendors = vendors; + } + + /** + * Concatenates all profile values. + * + * @return concatenated string conatining all profile values; + */ + private String concatenateValues() { + StringBuffer buf = new StringBuffer(); + append(buf, this.arch); + append(buf, this.archictectures); + append(buf, this.attribute); + append(buf, this.condition); + append(buf, this.conditions); + append(buf, this.conformance); + append(buf, this.conformances); + append(buf, this.lang); + append(buf, this.languages); + append(buf, this.operatingsystems); + append(buf, this.os); + append(buf, this.revision); + append(buf, this.revisions); + append(buf, this.role); + append(buf, this.roles); + append(buf, this.securities); + append(buf, this.security); + append(buf, this.userlevel); + append(buf, this.userlevels); + append(buf, this.vendor); + append(buf, this.vendors); + return buf.toString(); + } + + private void append(StringBuffer buf, String string) { + if (string == null) { + return; + } + buf.append(string); + } + + private void append(StringBuffer buf, String[] strings) { + if (strings == null) { + return; + } + for (int i = 0; i < strings.length; i++) { + buf.append(strings[i]); + } + } + + public String getSeparator() { + int startchar = 33; + String values = this.concatenateValues(); + while (values.indexOf(startchar) != -1) { + startchar++; + } + return new String(new byte[] { (byte) startchar }); + } + + public void setParameters(Transformer t) { + String s = this.getSeparator(); + t.setParameter("profile.separator", s); + setParameter(t, "profile.arch", arch, archictectures, s); + setParameter(t, "profile.condition", condition, conditions, s); + setParameter(t, "profile.conformance", conformance, conformances, s); + setParameter(t, "profile.lang", lang, languages, s); + setParameter(t, "profile.os", os, operatingsystems, s); + setParameter(t, "profile.revision", revision, revisions, s); + setParameter(t, "profile.role", role, roles, s); + setParameter(t, "profile.security", security, securities, s); + setParameter(t, "profile.userlevel", userlevel, userlevels, s); + setParameter(t, "profile.vendor", vendor, vendors, s); + + if (attribute != null && attribute.length() != 0 && value != null + && value.length() != 0) { + t.setParameter("profile.attribute", attribute); + t.setParameter("profile.value", value); + } + } + + public static void setParameter(Transformer transformer, String parameter, + String singlevalue, String[] multivalue, String separator) { + if ((multivalue == null || multivalue.length == 0) + && (singlevalue != null) && (!"".equals(singlevalue))) { + transformer.setParameter(parameter, singlevalue); + } else if (multivalue != null && multivalue.length != 0) { + transformer.setParameter(parameter, join(multivalue, separator)); + } + } + + private static String join(String[] strings, String separator) { + StringBuffer joined = new StringBuffer(); + for (int i = 0; i < strings.length; i++) { + if (i != 0) { + joined.append(separator); + } + joined.append(strings[i]); + } + return joined.toString(); + } +} Index: pom.xml =================================================================== --- pom.xml (revision 4465) +++ pom.xml (working copy) @@ -22,6 +22,13 @@