001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.doc.maven.utils; 018 019import org.apache.commons.io.DirectoryWalker; 020import org.apache.commons.io.FileUtils; 021 022import javax.xml.transform.Source; 023import javax.xml.transform.Transformer; 024import javax.xml.transform.TransformerConfigurationException; 025import javax.xml.transform.TransformerException; 026import javax.xml.transform.TransformerFactory; 027import javax.xml.transform.stream.StreamResult; 028import javax.xml.transform.stream.StreamSource; 029import java.io.ByteArrayInputStream; 030import java.io.File; 031import java.io.FileFilter; 032import java.io.IOException; 033import java.nio.charset.Charset; 034import java.util.ArrayList; 035import java.util.Arrays; 036import java.util.Collection; 037import java.util.List; 038 039/** 040 * Apply and XSL transformation to DocBook XML files. 041 */ 042public class XmlTransformer extends DirectoryWalker<File> { 043 044 /** 045 * Construct an updater to match DocBook XML files. 046 * 047 * <p> 048 * 049 * The files are updated in place. 050 * 051 * <p> 052 * 053 * The XSL resource must be on the classpath, 054 * and so you probably want to extend this with your own transformer class. 055 * 056 * @param filterToMatch Filter to match XML files. 057 * @param xslResource Path to XSL resource. 058 */ 059 public XmlTransformer(final FileFilter filterToMatch, final String xslResource) { 060 super(filterToMatch, -1); 061 062 try { 063 this.transformer = getTransformer(xslResource); 064 } catch (IOException ie) { 065 System.err.println(Arrays.toString(ie.getStackTrace())); 066 System.exit(1); 067 } catch (TransformerConfigurationException tce) { 068 System.err.println(Arrays.toString(tce.getStackTrace())); 069 System.exit(1); 070 } 071 } 072 073 /** 074 * Construct an updater to match DocBook XML files. 075 * 076 * <p> 077 * 078 * The files are updated in place. 079 * 080 * @param filterToMatch Filter to match XML files. 081 * @param xsl XSL as string. 082 */ 083 public XmlTransformer(final String xsl, final FileFilter filterToMatch) { 084 super(filterToMatch, -1); 085 086 try { 087 this.transformer = getTransformerForString(xsl); 088 } catch (TransformerConfigurationException tce) { 089 System.err.println(Arrays.toString(tce.getStackTrace())); 090 System.exit(1); 091 } 092 } 093 094 private Transformer transformer; 095 096 private Transformer getTransformer(final String xslResource) 097 throws IOException, TransformerConfigurationException { 098 TransformerFactory factory = TransformerFactory.newInstance(); 099 Source xslt = new StreamSource(getClass().getResource(xslResource).openStream()); 100 return factory.newTransformer(xslt); 101 } 102 103 private Transformer getTransformerForString(final String xsl) throws TransformerConfigurationException { 104 TransformerFactory factory = TransformerFactory.newInstance(); 105 Source xslt = new StreamSource(new ByteArrayInputStream(xsl.getBytes(Charset.forName("UTF-8")))); 106 return factory.newTransformer(xslt); 107 } 108 109 /** 110 * Update files that match the filter. 111 * 112 * @param startDirectory 113 * Base directory under which to update files, recursively 114 * @return List of updated files 115 * @throws java.io.IOException 116 * Something went wrong changing a file's content. 117 */ 118 public final List<File> update(final File startDirectory) throws IOException { 119 List<File> results = new ArrayList<File>(); 120 walk(startDirectory, results); 121 return results; 122 } 123 124 /** 125 * Update files that match, adding them to the results. 126 * 127 * @param file 128 * File to update 129 * @param depth 130 * Not used 131 * @param results 132 * List of files updated 133 * @throws java.io.IOException 134 * Something went wrong changing a file's content. 135 */ 136 @Override 137 protected final void handleFile(final File file, 138 final int depth, 139 final Collection<File> results) 140 throws IOException { 141 if (file.isFile()) { 142 try { 143 Source xml = new StreamSource(file); 144 File tmpFile = File.createTempFile(file.getName(), ".tmp"); 145 transformer.transform(xml, new StreamResult(tmpFile)); 146 147 FileUtils.deleteQuietly(file); 148 FileUtils.moveFile(tmpFile, file); 149 results.add(file); 150 } catch (TransformerException te) { 151 throw new IOException(te.getMessageAndLocation(), te); 152 } 153 } 154 } 155}