View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.rat.documentation;
20  
21  import java.io.BufferedWriter;
22  import java.io.File;
23  import java.io.FileFilter;
24  import java.io.IOException;
25  import java.lang.reflect.InvocationTargetException;
26  import java.nio.charset.StandardCharsets;
27  import java.nio.file.Files;
28  
29  import org.apache.commons.io.filefilter.DirectoryFileFilter;
30  import org.apache.commons.io.filefilter.OrFileFilter;
31  import org.apache.commons.io.filefilter.SuffixFileFilter;
32  import org.apache.rat.api.Document;
33  import org.apache.rat.api.RatException;
34  import org.apache.rat.document.DocumentName;
35  import org.apache.rat.document.DocumentNameMatcher;
36  import org.apache.rat.document.FileDocument;
37  import org.apache.rat.documentation.velocity.RatTool;
38  import org.apache.rat.report.RatReport;
39  import org.apache.rat.walker.DirectoryWalker;
40  import org.apache.velocity.Template;
41  import org.apache.velocity.VelocityContext;
42  import org.apache.velocity.app.VelocityEngine;
43  import org.apache.velocity.runtime.RuntimeConstants;
44  import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
45  import org.apache.velocity.tools.generic.EscapeTool;
46  
47  /**
48   * Uses Apache Velocity to write a document containing RAT configuration information.
49   *
50   * @see <a href="https://velocity.apache.org/">Apache Velocity</a>
51   */
52  public class Exporter {
53  
54      @Override
55      public String toString() {
56          return "Documentation exporter";
57      }
58  
59      /**
60       * Executes the generation of documentation from a configuration definition.
61       * Arguments are
62       * <ol>
63       * <li>Template directory - the top level directory in a tree of Velocity templates. The process scans the directory
64       * tree looking for files ending in {@code .vm} and processes them.</li>
65       * <li>Output directory - The top level directory to writhe the processed files to. The process removes the {@code .vm}
66       * from the input file name and writes the resulting file to an equivalent directory entry in the output directory.</li>
67       * </ol>
68       *
69       * @param args the arguments
70       * @throws IOException on IO error.
71       * @throws ClassNotFoundException if the configuration is not found.
72       * @throws NoSuchMethodException if the method name is not found.
73       * @throws InvocationTargetException if the method can not be invoked.
74       * @throws InstantiationException if the class can not be instantiated.
75       * @throws IllegalAccessException if there are access restrictions on the class.
76       * @throws RatException on RAT processing error.
77       */
78      public static void main(final String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException,
79              InvocationTargetException, InstantiationException, IllegalAccessException, RatException {
80          String templateDir = args[0];
81          String outputDir = args[1];
82  
83          // create a DirectoryWalker to walk the template tree.
84          File sourceDir = new File(templateDir);
85          DocumentName sourceName = DocumentName.builder(sourceDir).build();
86          FileFilter fileFilter = new OrFileFilter(new SuffixFileFilter(".vm"), DirectoryFileFilter.INSTANCE);
87          Document document = new FileDocument(sourceName, sourceDir, new DocumentNameMatcher(fileFilter));
88          DirectoryWalker walker = new DirectoryWalker(document);
89  
90          // create a rewriter that writes to the target directory.
91          DocumentName targetDir = DocumentName.builder(new File(outputDir)).build();
92  
93          // have the walker process clean and then the rewrite.
94          walker.run(new Cleaner(targetDir));
95          walker.run(new Rewriter(targetDir));
96      }
97  
98      /**
99       * A RatReport implementation that processes the {@code .vm} files in the template tree and writes the
100      * results to the output tree.
101      */
102     private static class Rewriter implements RatReport {
103         /**
104          * The base directory we are targeting for output
105          */
106         private final DocumentName targetDir;
107         /**
108          * The name of the root dir we are reading from
109          */
110         private final DocumentName rootDir;
111         /**
112          * The configured velocity engine
113          */
114         private final VelocityEngine velocityEngine;
115         /**
116          * The context for Velocity
117          */
118         private final VelocityContext context;
119 
120         /**
121          * Create a rewriter.
122          *
123          * @param targetDir the root of the output directory tree.
124          */
125         Rewriter(final DocumentName targetDir) {
126             this.targetDir = targetDir;
127             this.rootDir = DocumentName.builder(new File(".")).build();
128             velocityEngine = new VelocityEngine();
129             velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
130             velocityEngine.setProperty("file.resource.loader.class", FileResourceLoader.class.getName());
131             velocityEngine.init();
132             context = new VelocityContext();
133             context.put("esc", new EscapeTool());
134             context.put("rat", new RatTool());
135         }
136 
137         /**
138          * Processes the input document and creates an output document at an equivalent place in the output tree.
139          *
140          * @param document the input document.
141          */
142         @Override
143         public void report(final Document document) {
144             String localized = document.getName().localized();
145             DocumentName outputFile = targetDir.resolve(localized.substring(0, localized.length() - 3));
146             DocumentName relativeFile = DocumentName.builder(document.getName()).setBaseName(rootDir).build();
147             try {
148                 final File file = outputFile.asFile();
149                 if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
150                     throw new IOException("Unable to create directory: " + file.getParentFile());
151                 }
152                 final Template template = velocityEngine.getTemplate(relativeFile.localized());
153 
154                 try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
155                     template.merge(context, writer);
156                 }
157             } catch (IOException e) {
158                 throw new RuntimeException(e);
159             }
160         }
161     }
162 
163     /**
164      * A RatReport implementation that processes the {@code .vm} files in the template tree and writes the
165      * results to the output tree.
166      */
167     private static class Cleaner implements RatReport {
168         /**
169          * The base directory we are targeting for output
170          */
171         private final DocumentName targetDir;
172 
173         /**
174          * Create a rewriter.
175          *
176          * @param targetDir the root of the output directory tree.
177          */
178         Cleaner(final DocumentName targetDir) {
179             this.targetDir = targetDir;
180         }
181 
182         /**
183          * Processes the input document and creates an output document at an equivalent place in the output tree.
184          *
185          * @param document the input document.
186          */
187         @Override
188         public void report(final Document document) {
189             String localized = document.getName().localized();
190             DocumentName outputFile = targetDir.resolve(localized.substring(0, localized.length() - 3));
191             try {
192                 final File file = outputFile.asFile();
193                 if (file.exists()) {
194                     Files.delete(file.toPath());
195                 }
196             } catch (IOException e) {
197                 throw new RuntimeException(e);
198             }
199         }
200     }
201 }