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