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.commons.io.IOUtils;
23 import org.apache.maven.jxr.pacman.ClassType;
24 import org.apache.maven.jxr.pacman.PackageManager;
25 import org.apache.maven.jxr.pacman.PackageType;
26 import org.apache.maven.jxr.log.VelocityLogger;
27 import org.apache.maven.jxr.log.Log;
28 import org.apache.oro.text.perl.Perl5Util;
29 import org.apache.velocity.Template;
30 import org.apache.velocity.VelocityContext;
31 import org.apache.velocity.app.VelocityEngine;
32
33 import java.io.File;
34 import java.io.FileWriter;
35 import java.util.Enumeration;
36 import java.util.HashMap;
37 import java.util.Iterator;
38 import java.util.Map;
39 import java.util.TreeMap;
40
41 /**
42 * This class creates the navigational pages for jxr's cross-referenced source
43 * files. The navigation is inspired by javadoc, so it should have a familiar feel.
44 *
45 * Creates the following files:
46 * <ul>
47 * <li><code>index.html</code> main index containing the frameset</li>
48 * <li><code>overview-frame.html</code> list of the project's packages (top left)</li>
49 * <li><code>allclasses-frame.html</code> list of all classes in the project (bottom left)</li>
50 * <li><code>overview-summary.html</code> top-level listing of the project's packages (main frame)</li>
51 *
52 * <li>
53 * Package specific:
54 * <ul>
55 * <li><code>package-summary.html</code> listing of all classes in this package (main frame)</li>
56 * <li><code>package-frame.html</code> listing of all classes in this package (bottom left)</li>
57 * </ul>
58 * </li>
59 * </ul>
60 *
61 * @author <a href="mailto:bellingard@gmail.com">Fabrice Bellingard </a>
62 * @author <a href="mailto:brian@brainslug.org">Brian Leonard</a>
63 * @version $Id: DirectoryIndexer.java 1160901 2011-08-23 22:09:33Z bimargulies $
64 */
65 public class DirectoryIndexer
66 {
67 /*
68 * JavaCodeTransform uses this to cross-reference package references
69 * with that package's main summary page.
70 */
71 static final String INDEX = "package-summary.html";
72
73 /*
74 * Path to the root output directory.
75 */
76 private String root;
77
78 /*
79 * Package Manager for this project.
80 */
81 private PackageManager packageManager;
82
83 /*
84 * see the getter/setter docs for these properties
85 */
86 private String outputEncoding;
87
88 private String templateDir;
89
90 private String windowTitle;
91
92 private String docTitle;
93
94 private String bottom;
95
96 /**
97 * Constructor for the DirectoryIndexer object
98 *
99 * @param packageManager PackageManager for this project
100 * @param root Path of the root output directory
101 */
102 public DirectoryIndexer( PackageManager packageManager, String root )
103 {
104 this.packageManager = packageManager;
105 this.root = root;
106 }
107
108 /**
109 * OutputEncoding is the encoding of output files.
110 *
111 * @param outputEncoding output Encoding
112 */
113 public void setOutputEncoding( String outputEncoding )
114 {
115 this.outputEncoding = outputEncoding;
116 }
117
118 /**
119 * see setOutputEncoding(String)
120 */
121 public String getOutputEncoding()
122 {
123 return outputEncoding;
124 }
125
126 /**
127 * TemplateDir is the location of the jelly template files used
128 * to generate the navigation pages.
129 *
130 * @param templateDir location of the template directory
131 */
132 public void setTemplateDir( String templateDir )
133 {
134 this.templateDir = templateDir;
135 }
136
137 /**
138 * see setTemplateDir(String)
139 */
140 public String getTemplateDir()
141 {
142 return templateDir;
143 }
144
145 /**
146 * WindowTitle is used in the output's <title> tags
147 * see the javadoc documentation for the property of the same name
148 *
149 * @param windowTitle the <title> attribute
150 */
151 public void setWindowTitle( String windowTitle )
152 {
153 this.windowTitle = windowTitle;
154 }
155
156 /**
157 * see setWindowTitle(String)
158 *
159 * @see #setWindowTitle(String) setWindowTitle
160 */
161 public String getWindowTitle()
162 {
163 return windowTitle;
164 }
165
166 /**
167 * DocTitle is used as a page heading for the summary files
168 * see the javadoc documentation for the property of the same name
169 *
170 * @param docTitle major page heading
171 */
172 public void setDocTitle( String docTitle )
173 {
174 this.docTitle = docTitle;
175 }
176
177 /**
178 * see setDocTitle(String)
179 *
180 * @see #setDocTitle(String) setDocTitle
181 */
182 public String getDocTitle()
183 {
184 return docTitle;
185 }
186
187 /**
188 * Bottom is a footer for the navigation pages, usually a copyright
189 * see the javadoc documentation for the property of the same name
190 *
191 * @param bottom page footer
192 */
193 public void setBottom( String bottom )
194 {
195 this.bottom = bottom;
196 }
197
198 /**
199 * see setBottom(String)
200 *
201 * @see #setBottom(String) setBottom
202 */
203 public String getBottom()
204 {
205 return bottom;
206 }
207
208 /**
209 * Does the actual indexing.
210 *
211 * @throws JxrException If something went wrong
212 */
213 public void process( Log log )
214 throws JxrException
215 {
216 Map info = getPackageInfo();
217
218 VelocityEngine engine = new VelocityEngine();
219 setProperties( engine, log );
220 try
221 {
222 engine.init();
223 }
224 catch ( Exception e )
225 {
226 throw new JxrException( "Error initializing Velocity", e );
227 }
228
229 VelocityContext context = new VelocityContext();
230 context.put( "outputEncoding", getOutputEncoding() );
231 context.put( "windowTitle", getWindowTitle() );
232 context.put( "docTitle", getDocTitle() );
233 context.put( "bottom", getBottom() );
234 context.put( "info", info );
235
236 doVelocity( "index", root, context, engine );
237 doVelocity( "overview-frame", root, context, engine );
238 doVelocity( "allclasses-frame", root, context, engine );
239 doVelocity( "overview-summary", root, context, engine );
240
241 Iterator iter = ( (Map) info.get( "allPackages" ) ).values().iterator();
242 while ( iter.hasNext() )
243 {
244 Map pkgInfo = (Map) iter.next();
245
246 VelocityContext subContext = new VelocityContext( context );
247 subContext.put( "pkgInfo", pkgInfo );
248
249 String outDir = root + "/" + (String) pkgInfo.get( "dir" );
250 doVelocity( "package-summary", outDir, subContext, engine );
251 doVelocity( "package-frame", outDir, subContext, engine );
252 }
253 }
254
255 /*
256 * Set Velocity properties to find templates
257 */
258 private void setProperties( VelocityEngine engine, Log log )
259 {
260 File templateDirFile = new File( getTemplateDir() );
261 if ( templateDirFile.isAbsolute() )
262 {
263 // the property has been overridden: need to use a FileResourceLoader
264 engine.setProperty( "resource.loader", "file" );
265 engine.setProperty( "file.resource.loader.class",
266 "org.apache.velocity.runtime.resource.loader.FileResourceLoader" );
267 engine.setProperty( "file.resource.loader.path", templateDirFile.toString() );
268 }
269 else
270 {
271 // use of the default templates
272 engine.setProperty( "resource.loader", "classpath" );
273 engine.setProperty( "classpath.resource.loader.class",
274 "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
275 }
276 // avoid "unable to find resource 'VM_global_library.vm' in any resource loader."
277 engine.setProperty( "velocimacro.library", "" );
278 engine.setProperty( Log.class.getName(), log );
279 engine.setProperty( "runtime.log.logsystem.class", VelocityLogger.class.getName() );
280 }
281
282 /*
283 * Generate the HTML file according to the Velocity template
284 */
285 private void doVelocity( String templateName, String outDir, VelocityContext context, VelocityEngine engine )
286 throws JxrException
287 {
288 // output file
289 File file = new File( outDir, templateName + ".html" );
290 file.getParentFile().mkdirs();
291 FileWriter writer = null;
292
293 try
294 {
295 writer = new FileWriter( file );
296
297 // template file
298 StringBuffer templateFile = new StringBuffer();
299 File templateDirFile = new File( getTemplateDir() );
300 if ( !templateDirFile.isAbsolute() )
301 {
302 // default templates
303 templateFile.append( getTemplateDir() );
304 templateFile.append( "/" );
305 }
306 templateFile.append( templateName );
307 templateFile.append( ".vm" );
308 Template template = engine.getTemplate( templateFile.toString() );
309
310 // do the merge
311 template.merge( context, writer );
312 writer.flush();
313 }
314 catch ( Exception e )
315 {
316 throw new JxrException( "Error merging velocity template", e );
317 }
318 finally
319 {
320 IOUtils.closeQuietly( writer );
321 }
322 }
323
324 /*
325 * Creates a Map of other Maps containing information about
326 * this project's packages and classes, obtained from the PackageManager.
327 *
328 * allPackages collection of Maps with package info, with the following format
329 * {name} package name (e.g., "org.apache.maven.jxr")
330 * {dir} package dir relative to the root output dir (e.g., "org/apache/maven/jxr")
331 * {rootRef} relative link to root output dir (e.g., "../../../../") note trailing slash
332 * {classes} collection of Maps with class info
333 * {name} class name (e.g., "DirectoryIndexer")
334 * {dir} duplicate of package {dir}
335 *
336 * allClasses collection of Maps with class info, format as above
337 *
338 */
339 private Map getPackageInfo()
340 {
341 TreeMap allPackages = new TreeMap();
342 TreeMap allClasses = new TreeMap();
343 Perl5Util perl = new Perl5Util();
344
345 Enumeration packages = packageManager.getPackageTypes();
346 while ( packages.hasMoreElements() )
347 {
348 PackageType pkg = (PackageType) packages.nextElement();
349 String pkgName = pkg.getName();
350 String pkgDir = perl.substitute( "s/\\./\\//g", pkgName );
351 String rootRef = perl.substitute( "s/[^\\.]*(\\.|$)/..\\//g", pkgName );
352
353 // special case for the default package
354 // javadoc doesn't deal with it, but it's easy for us
355 if ( pkgName.length() == 0 )
356 {
357 pkgName = "(default package)";
358 pkgDir = ".";
359 rootRef = "./";
360 }
361
362 TreeMap pkgClasses = new TreeMap();
363 Enumeration classes = pkg.getClassTypes();
364 while ( classes.hasMoreElements() )
365 {
366 ClassType clazz = (ClassType) classes.nextElement();
367
368 String className = clazz.getName();
369 Map classInfo = new HashMap();
370 if ( clazz.getFilename() != null )
371 {
372 classInfo.put( "filename", clazz.getFilename() );
373 }
374 else
375 {
376 classInfo.put( "filename", "" );
377 }
378 classInfo.put( "name", className );
379 classInfo.put( "dir", pkgDir );
380
381 pkgClasses.put( className, classInfo );
382 allClasses.put( className, classInfo );
383 }
384
385 Map pkgInfo = new HashMap();
386 pkgInfo.put( "name", pkgName );
387 pkgInfo.put( "dir", pkgDir );
388 pkgInfo.put( "classes", pkgClasses );
389 pkgInfo.put( "rootRef", rootRef );
390 allPackages.put( pkgName, pkgInfo );
391 }
392
393 Map info = new HashMap();
394 info.put( "allPackages", allPackages );
395 info.put( "allClasses", allClasses );
396
397 return info;
398 }
399 }