1 package org.apache.maven.jxr;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.maven.jxr.ant.DirectoryScanner;
23 import org.apache.maven.jxr.log.Log;
24 import org.apache.maven.jxr.pacman.FileManager;
25 import org.apache.maven.jxr.pacman.PackageManager;
26
27 import java.io.File;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.List;
33 import java.util.Locale;
34
35 /**
36 * Main entry point into Maven used to kick off the XReference code building.
37 *
38 * @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>
39 * @version $Id: JXR.java 1544863 2013-11-23 18:54:06Z michaelo $
40 */
41 public class JXR
42 {
43 /**
44 * The Log.
45 */
46 private Log log;
47
48 /**
49 * The default list of include patterns to use.
50 */
51 private static final String[] DEFAULT_INCLUDES = {"**/*.java"};
52
53 /**
54 * Path to destination.
55 */
56 private String dest = "";
57
58 private Locale locale;
59
60 private String inputEncoding;
61
62 private String outputEncoding;
63
64 /**
65 * Relative path to javadocs, suitable for hyperlinking.
66 */
67 private String javadocLinkDir;
68
69 /**
70 * Handles taking .java files and changing them into html. "More than meets
71 * the eye!" :)
72 */
73 private JavaCodeTransform transformer;
74
75 /**
76 * The revision of the module currently being processed.
77 */
78 private String revision;
79
80 /**
81 * The list of exclude patterns to use.
82 */
83 private String[] excludes = null;
84
85 /**
86 * The list of include patterns to use.
87 */
88 private String[] includes = DEFAULT_INCLUDES;
89
90 /**
91 * Now that we have instantiated everything. Process this JXR task.
92 *
93 * @param packageManager
94 * @param source
95 * @param bottom
96 * @throws IOException
97 */
98 public void processPath( PackageManager packageManager, String source, String bottom )
99 throws IOException
100 {
101 this.transformer = new JavaCodeTransform( packageManager );
102
103 DirectoryScanner ds = new DirectoryScanner();
104 // I'm not sure why we don't use the directoryScanner in packageManager,
105 // but since we don't we need to set includes/excludes here as well
106 ds.setExcludes( excludes );
107 ds.setIncludes( includes );
108 ds.addDefaultExcludes();
109
110 File dir = new File( source );
111
112 if ( !dir.exists() )
113 {
114 if ( !dir.mkdirs() )
115 {
116 throw new IllegalStateException(
117 "Your source directory does not exist and could not be created:" + source );
118 }
119 }
120
121 ds.setBasedir( source );
122 ds.scan();
123
124 //now get the list of included files
125
126 String[] files = ds.getIncludedFiles();
127
128 for ( int i = 0; i < files.length; ++i )
129 {
130 String src = source + System.getProperty( "file.separator" ) + files[i];
131
132 if ( isJavaFile( src ) )
133 {
134 transform( src, getDestination( source, src ), bottom );
135 }
136
137 }
138 }
139
140 /**
141 * Check to see if the file is a Java source file.
142 *
143 * @param filename The name of the file to check
144 * @return <code>true</true> if the file is a Java file
145 */
146 public static boolean isJavaFile( String filename )
147 {
148 File file = new File( filename );
149 return filename.endsWith( ".java" ) && file.length() > 0;
150 }
151
152 /**
153 * Check to see if the file is an HTML file.
154 *
155 * @param filename The name of the file to check
156 * @return <code>true</true> if the file is an HTML file
157 */
158 public static boolean isHtmlFile( String filename )
159 {
160 return filename.endsWith( ".html" );
161 }
162
163 /**
164 * Get the path to the destination files.
165 *
166 * @return The path to the destination files
167 */
168 public String getDest()
169 {
170 return this.dest;
171 }
172
173 /**
174 * @param dest
175 */
176 public void setDest( String dest )
177 {
178 this.dest = dest;
179 }
180
181 /**
182 * @param locale
183 */
184 public void setLocale( Locale locale )
185 {
186 this.locale = locale;
187 }
188
189 /**
190 * @param inputEncoding
191 */
192 public void setInputEncoding( String inputEncoding )
193 {
194 this.inputEncoding = inputEncoding;
195 }
196
197 /**
198 * @param outputEncoding
199 */
200 public void setOutputEncoding( String outputEncoding )
201 {
202 this.outputEncoding = outputEncoding;
203 }
204
205 /**
206 * @param javadocLinkDir
207 */
208 public void setJavadocLinkDir( String javadocLinkDir )
209 {
210 // get a relative link to the javadocs
211 this.javadocLinkDir = javadocLinkDir;
212 }
213
214 /**
215 * @param transformer
216 */
217 public void setTransformer( JavaCodeTransform transformer )
218 {
219 this.transformer = transformer;
220 }
221
222 /**
223 * @param revision
224 */
225 public void setRevision( String revision )
226 {
227 this.revision = revision;
228 }
229
230 /**
231 * @param log
232 */
233 public void setLog( Log log )
234 {
235 this.log = log;
236 }
237
238 /**
239 * @param sourceDirs
240 * @param templateDir
241 * @param windowTitle
242 * @param docTitle
243 * @param bottom
244 * @throws IOException
245 * @throws JxrException
246 */
247 public void xref( List sourceDirs, String templateDir, String windowTitle, String docTitle, String bottom )
248 throws IOException, JxrException
249 {
250 // first collect package and class info
251 FileManager fileManager = new FileManager();
252 fileManager.setEncoding( inputEncoding );
253
254 PackageManager pkgmgr = new PackageManager( log, fileManager );
255 pkgmgr.setExcludes( excludes );
256 pkgmgr.setIncludes( includes );
257
258 // go through each source directory and xref the java files
259 for ( Iterator i = sourceDirs.iterator(); i.hasNext(); )
260 {
261 String path = (String) i.next();
262 path = new File( path ).getCanonicalPath();
263
264 pkgmgr.process( path );
265
266 processPath( pkgmgr, path, bottom );
267 }
268
269 // once we have all the source files xref'd, create the index pages
270 DirectoryIndexer indexer = new DirectoryIndexer( pkgmgr, dest );
271 indexer.setOutputEncoding( outputEncoding );
272 indexer.setTemplateDir( templateDir );
273 indexer.setWindowTitle( windowTitle );
274 indexer.setDocTitle( docTitle );
275 indexer.setBottom( bottom );
276 indexer.process( log );
277 }
278
279 // ----------------------------------------------------------------------
280 // private methods
281 // ----------------------------------------------------------------------
282
283 /**
284 * Given a filename get the destination on the filesystem of where to store
285 * the to be generated HTML file. Pay attention to the package name.
286 *
287 * @param source
288 * @param filename
289 * @return A String with the store destination.
290 */
291 private String getDestination( String source, String filename )
292 {
293 //remove the source directory from the filename.
294
295 String dest = filename.substring( source.length(), filename.length() );
296
297 int start = 0;
298 int end = dest.indexOf( ".java" );
299
300 if ( end != -1 )
301 {
302 //remove the .java from the filename
303 dest = dest.substring( start, end );
304 }
305
306 //add the destination directory to the filename.
307 dest = this.getDest() + dest;
308
309 //add .html to the filename
310
311 dest = dest + ".html";
312
313 return dest;
314 }
315
316 /**
317 * Given a source file transform it into HTML and write it to the
318 * destination (dest) file.
319 *
320 * @param source The java source file
321 * @param dest The directory to put the HTML into
322 * @param bottom The bottom footer text just as in the package pages
323 * @throws IOException Thrown if the transform can't happen for some reason.
324 */
325 private void transform( String source, String dest, String bottom )
326 throws IOException
327 {
328 log.debug( source + " -> " + dest );
329
330 // get a relative link to the javadocs
331 String javadoc = javadocLinkDir != null ? getRelativeLink( dest, javadocLinkDir ) : null;
332 transformer.transform( source, dest, locale, inputEncoding, outputEncoding, javadoc,
333 this.revision, bottom );
334 }
335
336 /**
337 * Creates a relative link from one directory to another.
338 *
339 * Example:
340 * given <code>/foo/bar/baz/oink</code>
341 * and <code>/foo/bar/schmoo</code>
342 *
343 * this method will return a string of <code>"../../schmoo/"</code>
344 *
345 * @param fromDir The directory from which the link is relative.
346 * @param toDir The directory into which the link points.
347 * @return a String of format <code>"../../schmoo/"</code>
348 * @throws java.io.IOException If a problem is encountered while navigating through the directories.
349 */
350 private static String getRelativeLink( String fromDir, String toDir )
351 throws IOException
352 {
353 StringBuffer toLink = new StringBuffer(); // up from fromDir
354 StringBuffer fromLink = new StringBuffer(); // down into toDir
355
356 // create a List of toDir's parent directories
357 List parents = new LinkedList();
358 File f = new File( toDir );
359 f = f.getCanonicalFile();
360 while ( f != null )
361 {
362 parents.add( f );
363 f = f.getParentFile();
364 }
365
366 // walk up fromDir to find the common parent
367 f = new File( fromDir );
368 if ( !f.isDirectory() )
369 {
370 // Passed in a fromDir with a filename on the end - strip it
371 f = f.getParentFile();
372 }
373 f = f.getCanonicalFile();
374 f = f.getParentFile();
375 boolean found = false;
376 while ( f != null && !found )
377 {
378 for ( int i = 0; i < parents.size(); ++i )
379 {
380 File parent = (File) parents.get( i );
381 if ( f.equals( parent ) )
382 {
383 // when we find the common parent, add the subdirectories
384 // down to toDir itself
385 for ( int j = 0; j < i; ++j )
386 {
387 File p = (File) parents.get( j );
388 toLink.insert( 0, p.getName() + "/" );
389 }
390 found = true;
391 break;
392 }
393 }
394 f = f.getParentFile();
395 fromLink.append( "../" );
396 }
397
398 if ( !found )
399 {
400 throw new FileNotFoundException( fromDir + " and " + toDir + " have no common parent." );
401 }
402
403 return fromLink.append( toLink.toString() ).toString();
404 }
405
406 public void setExcludes( String[] excludes )
407 {
408 this.excludes = excludes;
409 }
410
411
412 public void setIncludes( String[] includes )
413 {
414 if ( includes == null )
415 {
416 // We should not include non-java files, so we use a sensible default pattern
417 this.includes = DEFAULT_INCLUDES;
418 }
419 else
420 {
421 this.includes = includes;
422 }
423 }
424 }