1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package projassist.readme;
17
18 import java.io.File;
19 import java.util.Iterator;
20 import java.util.Set;
21 import java.util.Stack;
22 import java.util.TreeSet;
23 import java.util.Vector;
24 import java.io.FileOutputStream;
25 import java.io.FileInputStream;
26
27 /***
28 * This is the Bean that is used in the Readme plugin.
29 *
30 * @author $Author: mkurjano $
31 * @version $Revision: 1.3 $, $Date: 2004/07/22 05:14:35 $
32 */
33 public final class ReadmePlugin {
34
35 /***
36 * Whether or not to debug.
37 * @todo Make this a bean property.
38 */
39 private static final boolean DEBUG = true;
40
41 /***
42 * The size of the buffer that is used when reading and writing files.
43 */
44 private static final int BUFFER_SIZE = 2048;
45
46 /***
47 * This is the base path that the plugin starts looking for files.
48 * This directory, and all of its subdirectories will be
49 * recursively searched for files.
50 */
51 private String rootPath = null;
52
53 /***
54 * This is the name of the file that we are looking for. By
55 * default it is set to <code>readme.xml</code>.
56 */
57 private String seekFileName = null;
58
59 /***
60 * This is the directory to which we will write the output.
61 */
62 private String outputDirectory = null;
63
64 /***
65 * This is the name of the file to which we will write the
66 * overview of our findings. This defaults to
67 * <code>readme-report.xml</code>.
68 */
69 private String outputReportFileName = null;
70
71 /***
72 * The number of files that this plugin processed.
73 */
74 private int processedCount = 0;
75
76 /***
77 * The baseDir of the current project. So we can exclude basedir/target.
78 */
79 private String baseDir = null;
80
81 private String reportHeader = ""
82 + "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \n"
83 + "<document> \n"
84 + " <properties> \n"
85 + " <author email=\"nobody@nobody.com\">Some Author</author> \n"
86 + " <title>Readme Files</title> \n"
87 + " </properties> \n"
88 + " <meta name=\"keyword\" content=\"readme,readme files\" /> \n"
89 + " <body> \n"
90 + " <section name=\"Readme Files\"> \n"
91 + " <p> \n";
92
93 private String reportFooter = ""
94 + " </p> \n"
95 + " </section> \n"
96 + " </body> \n"
97 + "</document> \n";
98
99 /***
100 * Default constructor, sets all values to their defaults.
101 *
102 * @see #ReadmePlugin(String, String, String, String, String)
103 */
104 public ReadmePlugin() {
105 this(null, null, null, null, null);
106 }
107
108 /***
109 * Constructor that sets all fields to given values.
110 *
111 * @param theRootPath The root directory that we will begin
112 * searching in.
113 * @param theSeekFileName The name of the file that we are looking
114 * for.
115 * @param theOutputDirectory The name of the directory that we
116 * will write all output to.
117 * @param theOutputReportFileName The name of the file that we
118 * will write the overview page of our findings.
119 * @param theBaseDir The base directory of the project we're
120 * working on.
121 *
122 * @see #setRootPath(String)
123 * @see #setSeekFileName(String)
124 * @see #setOutputDirectory(String)
125 * @see #setOutputReportFileName(String)
126 * @see #setBaseDir(String)
127 */
128 public ReadmePlugin(final String theRootPath,
129 final String theSeekFileName,
130 final String theOutputDirectory,
131 final String theOutputReportFileName,
132 final String theBaseDir) {
133 setRootPath(theRootPath);
134 setSeekFileName(theSeekFileName);
135 setOutputDirectory(theOutputDirectory);
136 setOutputReportFileName(theOutputReportFileName);
137 setBaseDir(theBaseDir);
138 }
139
140 /***
141 * Get the root search path.
142 *
143 * @return The root search path.
144 */
145 public String getRootPath() {
146 return this.rootPath;
147 }
148
149 /***
150 * Set the root search path. If <code>theRootPath</code> is
151 * <code>null</code>, then this value is set to <code>.</code>.
152 *
153 * @param theRootPath The root search path.
154 *
155 * @todo See if we can try to get the default from a system property.
156 */
157 public void setRootPath(final String theRootPath) {
158 if (null == theRootPath) {
159 this.rootPath = ".";
160 } else {
161 this.rootPath = theRootPath;
162 }
163 }
164
165 /***
166 * Get the filename to look for.
167 *
168 * @return The filename to look for.
169 */
170 public String getSeekFileName() {
171 return this.seekFileName;
172 }
173
174 /***
175 * Set the filename to look for. If <code>theSeekFileName</code>
176 * is <code>null</code>, then this value is set to
177 * <code>readme.xml</code>.
178 *
179 * @param theSeekFileName The file name to look for.
180 *
181 * @todo See if we can get the default from a system property.
182 */
183 public void setSeekFileName(final String theSeekFileName) {
184 if (null == theSeekFileName) {
185 this.seekFileName = "readme.xml";
186 } else {
187 this.seekFileName = theSeekFileName;
188 }
189 }
190
191 /***
192 * Get the base output directory.
193 *
194 * @return The base output directory.
195 */
196 public String getOutputDirectory() {
197 return this.outputDirectory;
198 }
199
200 /***
201 * Set the base output directory. If
202 * <code>theOutputDirectory</code> is <code>null</code>, then
203 * this value is set to <code>/tmp</code>.
204 *
205 * @param theOutputDirectory The base output directory.
206 *
207 * @todo See if we can get the default from a system property.
208 */
209 public void setOutputDirectory(final String theOutputDirectory) {
210 if (null == theOutputDirectory) {
211 this.outputDirectory = "/tmp";
212 } else {
213 this.outputDirectory = theOutputDirectory;
214 }
215 }
216
217 /***
218 * Get the output report file name.
219 *
220 * @return The output report file name.
221 */
222 public String getOutputReportFileName() {
223 return this.outputReportFileName;
224 }
225
226 /***
227 * Set the output report file name. If
228 * <code>theOutputReportFileName</code> is <code>null</code>, the
229 * this value is set to <code>readme-report.xml</code>.
230 *
231 * @param theOutputReportFileName The output report file name.
232 *
233 * @todo See if we can get the default from a system property.
234 */
235 public void setOutputReportFileName(final String theOutputReportFileName) {
236 if (null == theOutputReportFileName) {
237 this.outputReportFileName = "readme-report.xml";
238 } else {
239 this.outputReportFileName = theOutputReportFileName;
240 }
241 }
242
243 /***
244 * Get this project's base directory.
245 *
246 * @return This project's base directory.
247 */
248 public String getBaseDir() {
249 return this.baseDir;
250 }
251
252 /***
253 * Set the base dir of the project we're working in. If
254 * <code>theBaseDir</code> is <code>null</code> then this value is
255 * set to <code>/tmp</code>.
256 *
257 * @param theBaseDir The base directory of the project we're
258 * working on.
259 *
260 * @todo See if wew can get the default from a system property.
261 */
262 public void setBaseDir(final String theBaseDir) {
263 if (null == theBaseDir) {
264 this.baseDir = "/tmp";
265 } else {
266 this.baseDir = theBaseDir;
267 }
268 }
269
270 /***
271 * Get the number of files that were processed in this report.
272 *
273 * @return The number of files that were processed in this report.
274 */
275 public int getProcessedCount() {
276 return this.processedCount;
277 }
278
279 /***
280 * Execute this plugin.
281 *
282 * @throws Exception If something went wrong.
283 */
284 public void generateReport() throws Exception {
285 try {
286 Set files = populateFileList();
287 Set processedFileNames = new TreeSet();
288 int i = 0;
289 File outputDirectoryFile = new File(outputDirectory);
290
291 outputDirectoryFile.mkdirs();
292
293 if (DEBUG) {
294 System.out.println("Files that we are going to use:");
295 }
296
297 for (Iterator it = files.iterator(); it.hasNext(); i++) {
298 File next = (File) it.next();
299 String newFileName = getNewFileName(next);
300 File newFile = new File(outputDirectoryFile, newFileName);
301
302 if (DEBUG) {
303 System.out.println("File [" + i + "]: " + next);
304 System.out.println("File [" + i + "]: " + newFileName);
305 System.out.println("File [" + i + "]: " + newFile);
306 }
307
308 processedFileNames.add(newFileName);
309 copyFile(next, newFile);
310 }
311
312 writeOverview(processedFileNames);
313
314 this.processedCount = i;
315 } catch (Exception e) {
316 String msg = "Got exception when processing reports.";
317 System.err.println(msg);
318 System.err.println(e.getMessage() + "\n");
319 e.printStackTrace();
320 }
321 }
322
323 /***
324 * Populate a <code>{@link java.util.Set}</code> with all files
325 * that match the given file that are in or below the root
326 * directory.
327 *
328 * @note Currently this method excludes all subdirectories of
329 * ${basedir}/target/.
330 *
331 * @todo Get the excluded directories from a property - i.e. a set.
332 *
333 * @return A <code>{@link java.util.Set}</code> of all files that
334 * we are processing.
335 *
336 * @throws Exception If something went wrong.
337 */
338 private Set populateFileList() throws Exception {
339 Stack toEvaluate = initializeStack();
340 Set evaluated = new TreeSet();
341 Set files = new TreeSet();
342
343 while (!(toEvaluate.isEmpty())) {
344 File currentDir = (File) toEvaluate.pop();
345 File[] fileList = currentDir.listFiles();
346
347 for (int i = 0; i < fileList.length; i++) {
348 if (DEBUG) {
349 System.out.println("Processing file: " + fileList[i]);
350 }
351
352 if (fileList[i].isDirectory()) {
353 toEvaluate.push(fileList[i]);
354 } else if (fileList[i].getName().equals(seekFileName)) {
355 files.add(fileList[i]);
356 }
357 }
358 }
359
360 return files;
361 }
362
363 /***
364 * Create a new stack and add the root directory to it.
365 *
366 * @return A <code>{@link java.util.Stack}</code> that contains a
367 * <code>{@link java.io.File}</code> that is the root directory.
368 *
369 * @throws Exception If the given root directory is not a
370 * directory.
371 *
372 * @see #rootPath
373 */
374 private Stack initializeStack() throws Exception {
375 Stack stack = new Stack();
376 File root = new File(rootPath);
377
378 if (!root.isDirectory()) {
379 String msg = "Root path: "
380 + rootPath
381 + " is not actually a directory!";
382 System.err.println("FATAL: " + msg);
383 throw new Exception(msg);
384 }
385
386 stack.push(root);
387
388 return stack;
389 }
390
391 /***
392 * Get a String file name from a project descriptor.
393 *
394 * @param oldFileName The original file.
395 *
396 * @return The absolute path of the original file, with spaces,
397 * forward slashes, back slashes, and the system's path separator
398 * characters are replaced with underscores.
399 */
400 private String getNewFileName(File oldFileName) {
401 String path = oldFileName.getAbsolutePath();
402
403
404 String newFileName = path.replace(File.pathSeparatorChar, '_');
405
406
407
408
409
410 newFileName = newFileName.replace(' ', '_');
411 newFileName = newFileName.replace('/', '_');
412 newFileName = newFileName.replace('//', '_');
413
414 return newFileName;
415 }
416
417 /***
418 * Copy a file from one location to another.
419 *
420 * @param src The file descriptor of the source file to copy from.
421 * @param dest The File descriptor of the file to copy to.
422 *
423 * @todo Write out header and footer information
424 */
425 private void copyFile(File src, File dest) throws Exception {
426 FileInputStream fis = null;
427 FileOutputStream fos = null;
428 try {
429 fis = new FileInputStream(src);
430 fos = new FileOutputStream(dest);
431 int r = -1;
432 byte[] buf = new byte[BUFFER_SIZE];
433
434 while ((r = fis.read(buf, 0, BUFFER_SIZE)) > 0) {
435 fos.write(buf, 0, r);
436 }
437 } catch (Exception ex) {
438 throw ex;
439 } finally {
440 try {
441 if (null != fis) {
442 fis.close();
443 }
444 } catch (Exception e) {
445 throw e;
446 } finally {
447 if (null != fos) {
448 fos.close();
449 }
450 }
451 }
452 }
453
454 private void writeOverview(Set files) throws Exception {
455 File outputReport = new File(outputDirectory, outputReportFileName);
456 FileOutputStream fos = null;
457 try {
458 fos = new FileOutputStream(outputReport);
459
460
461 byte[] toWrite = reportHeader.getBytes();
462 fos.write(toWrite, 0, toWrite.length);
463
464
465 for (Iterator it = files.iterator(); it.hasNext();) {
466 String curr = (String) it.next();
467 curr = curr.replaceAll("//.xml", ".html");
468 String out = "<a href=\"" + curr + "\">" + curr + "</a><br />";
469
470 toWrite = out.getBytes();
471 fos.write(toWrite, 0, toWrite.length);
472 }
473
474
475 toWrite = reportFooter.getBytes();
476 fos.write(toWrite, 0, toWrite.length);
477 } catch (Exception e) {
478 throw e;
479 } finally {
480 if (null != fos) {
481 fos.close();
482 }
483 }
484 }
485
486 public static void main(String[] args) throws Exception {
487 ReadmePlugin rp = new ReadmePlugin();
488
489 rp.setRootPath("/Users/mkurjano/cvswork/readme-plugin/");
490 rp.generateReport();
491 }
492 }