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.nio.charset.StandardCharsets;
26  import java.nio.file.Files;
27  
28  import org.apache.commons.io.filefilter.DirectoryFileFilter;
29  import org.apache.commons.io.filefilter.OrFileFilter;
30  import org.apache.commons.io.filefilter.SuffixFileFilter;
31  import org.apache.rat.api.Document;
32  import org.apache.rat.api.RatException;
33  import org.apache.rat.document.DocumentName;
34  import org.apache.rat.document.DocumentNameMatcher;
35  import org.apache.rat.document.FileDocument;
36  import org.apache.rat.documentation.velocity.RatTool;
37  import org.apache.rat.report.RatReport;
38  import org.apache.rat.walker.DirectoryWalker;
39  import org.apache.velocity.Template;
40  import org.apache.velocity.VelocityContext;
41  import org.apache.velocity.app.VelocityEngine;
42  import org.apache.velocity.runtime.RuntimeConstants;
43  import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
44  import org.apache.velocity.tools.generic.EscapeTool;
45  
46  /**
47   * Uses Apache Velocity to write a document containing RAT configuration information.
48   *
49   * @see <a href="https://velocity.apache.org/">Apache Velocity</a>
50   */
51  public class Exporter {
52  
53      @Override
54      public String toString() {
55          return "Documentation exporter";
56      }
57  
58      /**
59       * Executes the generation of documentation from a configuration definition.
60       * Arguments are
61       * <ol>
62       * <li>Template directory - the top level directory in a tree of Velocity templates. The process scans the directory
63       * tree looking for files ending in {@code .vm} and processes them.</li>
64       * <li>Output directory - The top level directory to writhe the processed files to. The process removes the {@code .vm}
65       * from the input file name and writes the resulting file to an equivalent directory entry in the output directory.</li>
66       * </ol>
67       *
68       * @param args the arguments
69       * @throws RatException on RAT processing error.
70       */
71      public static void main(final String[] args) throws
72              RatException {
73          String templateDir = args[0];
74          String outputDir = args[1];
75  
76          // create a DirectoryWalker to walk the template tree.
77          File sourceDir = new File(templateDir);
78          DocumentName sourceName = DocumentName.builder(sourceDir).build();
79          FileFilter fileFilter = new OrFileFilter(new SuffixFileFilter(".vm"), DirectoryFileFilter.INSTANCE);
80          Document document = new FileDocument(sourceName, sourceDir, new DocumentNameMatcher(fileFilter));
81          DirectoryWalker walker = new DirectoryWalker(document);
82  
83          // create a rewriter that writes to the target directory.
84          DocumentName targetDir = DocumentName.builder(new File(outputDir)).build();
85  
86          // have the walker process clean and then the rewrite.
87          walker.run(new Cleaner(targetDir));
88          walker.run(new Rewriter(targetDir));
89      }
90  
91      /**
92       * A RatReport implementation that processes the {@code .vm} files in the template tree and writes the
93       * results to the output tree.
94       */
95      private static class Rewriter implements RatReport {
96          /**
97           * The base directory we are targeting for output
98           */
99          private final DocumentName targetDir;
100         /**
101          * The name of the root dir we are reading from
102          */
103         private final DocumentName rootDir;
104         /**
105          * The configured velocity engine
106          */
107         private final VelocityEngine velocityEngine;
108         /**
109          * The context for Velocity
110          */
111         private final VelocityContext context;
112 
113         /**
114          * Create a rewriter.
115          *
116          * @param targetDir the root of the output directory tree.
117          */
118         Rewriter(final DocumentName targetDir) {
119             this.targetDir = targetDir;
120             this.rootDir = DocumentName.builder(new File(".")).build();
121             velocityEngine = new VelocityEngine();
122             velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
123             velocityEngine.setProperty("file.resource.loader.class", FileResourceLoader.class.getName());
124             velocityEngine.init();
125             context = new VelocityContext();
126             context.put("esc", new EscapeTool());
127             context.put("rat", new RatTool());
128         }
129 
130         /**
131          * Processes the input document and creates an output document at an equivalent place in the output tree.
132          *
133          * @param document the input document.
134          */
135         @Override
136         public void report(final Document document) {
137             String localized = document.getName().localized();
138             DocumentName outputFile = targetDir.resolve(localized.substring(0, localized.length() - 3));
139             DocumentName relativeFile = DocumentName.builder(document.getName()).setBaseName(rootDir).build();
140             try {
141                 final File file = outputFile.asFile();
142                 if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
143                     throw new IOException("Unable to create directory: " + file.getParentFile());
144                 }
145                 final Template template = velocityEngine.getTemplate(relativeFile.localized());
146 
147                 try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
148                     template.merge(context, writer);
149                 }
150             } catch (IOException e) {
151                 throw new RuntimeException(e);
152             }
153         }
154     }
155 
156     /**
157      * A RatReport implementation that processes the {@code .vm} files in the template tree and writes the
158      * results to the output tree.
159      *
160      * @param targetDir The base directory we are targeting for output
161      */
162         private record Cleaner(DocumentName targetDir) implements RatReport {
163         /**
164          * Create a rewriter.
165          *
166          * @param targetDir the root of the output directory tree.
167          */
168         private Cleaner {
169         }
170 
171             /**
172              * Processes the input document and creates an output document at an equivalent place in the output tree.
173              *
174              * @param document the input document.
175              */
176             @Override
177             public void report(final Document document) {
178                 String localized = document.getName().localized();
179                 DocumentName outputFile = targetDir.resolve(localized.substring(0, localized.length() - 3));
180                 try {
181                     final File file = outputFile.asFile();
182                     if (file.exists()) {
183                         Files.delete(file.toPath());
184                     }
185                 } catch (IOException e) {
186                     throw new RuntimeException(e);
187                 }
188             }
189         }
190 }