View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2013-2015 ForgeRock AS.
15   */
16  
17  package org.forgerock.doc.maven.utils;
18  
19  import org.apache.commons.io.DirectoryWalker;
20  import org.apache.commons.io.FileUtils;
21  
22  import javax.xml.transform.Source;
23  import javax.xml.transform.Transformer;
24  import javax.xml.transform.TransformerConfigurationException;
25  import javax.xml.transform.TransformerException;
26  import javax.xml.transform.TransformerFactory;
27  import javax.xml.transform.stream.StreamResult;
28  import javax.xml.transform.stream.StreamSource;
29  import java.io.ByteArrayInputStream;
30  import java.io.File;
31  import java.io.FileFilter;
32  import java.io.IOException;
33  import java.nio.charset.Charset;
34  import java.util.ArrayList;
35  import java.util.Arrays;
36  import java.util.Collection;
37  import java.util.List;
38  
39  /**
40   * Apply and XSL transformation to DocBook XML files.
41   */
42  public class XmlTransformer extends DirectoryWalker<File> {
43  
44      /**
45       * Construct an updater to match DocBook XML files.
46       *
47       * <p>
48       *
49       * The files are updated in place.
50       *
51       * <p>
52       *
53       * The XSL resource must be on the classpath,
54       * and so you probably want to extend this with your own transformer class.
55       *
56       * @param  filterToMatch    Filter to match XML files.
57       * @param  xslResource      Path to XSL resource.
58       */
59      public XmlTransformer(final FileFilter filterToMatch, final String xslResource) {
60          super(filterToMatch, -1);
61  
62          try {
63              this.transformer = getTransformer(xslResource);
64          } catch (IOException ie) {
65              System.err.println(Arrays.toString(ie.getStackTrace()));
66              System.exit(1);
67          } catch (TransformerConfigurationException tce) {
68              System.err.println(Arrays.toString(tce.getStackTrace()));
69              System.exit(1);
70          }
71      }
72  
73      /**
74       * Construct an updater to match DocBook XML files.
75       *
76       * <p>
77       *
78       * The files are updated in place.
79       *
80       * @param  filterToMatch    Filter to match XML files.
81       * @param  xsl              XSL as string.
82       */
83      public XmlTransformer(final String xsl, final FileFilter filterToMatch) {
84          super(filterToMatch, -1);
85  
86          try {
87              this.transformer = getTransformerForString(xsl);
88          } catch (TransformerConfigurationException tce) {
89              System.err.println(Arrays.toString(tce.getStackTrace()));
90              System.exit(1);
91          }
92      }
93  
94      private Transformer transformer;
95  
96      private Transformer getTransformer(final String xslResource)
97              throws IOException, TransformerConfigurationException {
98          TransformerFactory factory = TransformerFactory.newInstance();
99          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 }