View Javadoc

1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    *      http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  package gr.abiss.mvn.plugins.jstools;
15  
16  import gr.abiss.mvn.plugins.jstools.utils.FileSystemDirectoryUtils;
17  import java.io.BufferedOutputStream;
18  import java.io.ByteArrayOutputStream;
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileNotFoundException;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.io.PrintStream;
27  import java.nio.channels.FileChannel;
28  import java.util.ArrayList;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Locale;
32  import java.util.Set;
33  import org.apache.commons.io.IOUtils;
34  import org.apache.maven.reporting.MavenReportException;
35  import org.codehaus.plexus.archiver.ArchiverException;
36  import org.codehaus.plexus.archiver.UnArchiver;
37  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
38  import org.mozilla.javascript.tools.shell.Main;
39  
40  /***
41   * Goal to generate JavaScript documentation using the JSDoc Toolkit
42   * 
43   * @goal jsdoc
44   * @version $Id$
45   * @author manos
46   * 
47   */
48  public class JsDocMojo extends AbstractBaseJstoolsReport {
49  	/***
50  	 * The JSDoc template to use. Valid values are template directory names in
51  	 * the JSDoc Toolkit Distribution used or paths to an appropriate template
52  	 * directory. The default is JSDocs' "jsdoc" template.
53  	 * 
54  	 * @parameter expression="jsdoc"
55  	 */
56  	private String template;
57  
58  	/***
59  	 * A path pointing to a the desired JSDoc Toolkit directory (e.g.
60  	 * /home/username/stuff/jsdoc_toolkit-1.3.0). If no value is provided the
61  	 * plugin wil use its own internal version.
62  	 * 
63  	 * @parameter
64  	 */
65  	private String jsdocHome;
66  	
67  	/***
68  	 * Whether to include symbols tagged as private. Default is <code>false</code>.
69  	 * @parameter expression="false"
70  	 */
71  	private boolean includePrivate;
72  	
73  	/***
74  	 * Include all functions, even undocumented ones. Default is <code>false</code>.
75  	 * @parameter expression="false"
76  	 */
77  	private boolean includeUndocumented;
78  	
79  	/***
80  	 * Include all functions, even undocumented, underscored ones. Default is <code>false</code>.
81  	 * @parameter expression="false"
82  	 */
83  	private boolean includeUndocumentedUnderscored;
84  	
85  	/***
86  	 * Use the -j option, must be set to <code>false</code> for JSDoc Toolkit 1.x. or 
87  	 * <code>true</code> for JSDoc Toolkit version 2.0 and above. Default is <code>true</code>. 
88  	 * @parameter expression="true"
89  	 */
90  	private boolean jArgument;
91  	
92  
93  	/***
94  	 * Use JSDoc to generate Javascript API documentation
95  	 * 
96  	 * @see gr.abiss.mvn.plugins.jstools.AbstractBaseJstoolsReport#doGenerateReport(java.util.Locale)
97  	 */
98  	public void doGenerateReport(Locale defaultLocale)
99  			throws MavenReportException {
100 		// set the working directory, needed by jsdoc, override temporarily if
101 		// needed
102 		// (not sure if this has any effect outside the context VM)
103 		String systemJsdocDir = System.getProperty("jsdoc.dir");
104 		System.setProperty("jsdoc.dir", this.jsdocHome);
105 		if (systemJsdocDir != null) {
106 			getLog().debug("Temporarily switched the system's 'sdoc.dir' property to: "+System.getProperty("jsdoc.dir"));
107 		}
108 		// prepare the arguments to run.js
109 		List<String> args = new ArrayList<String>();
110 		// supress console output if level is INFO
111 		ByteArrayOutputStream baos = null;
112 		PrintStream ps = null;
113 		if(!this.getLog().isDebugEnabled()){
114 			baos = new ByteArrayOutputStream();
115 			ps = new PrintStream(baos);
116 			Main.setOut(ps);
117 		}
118 		String runJsPath = this.jsdocHome + "/app/run.js";
119 		args.add(runJsPath);
120 		if(this.includeUndocumented){
121 			args.add( "-a" );
122 		}
123 		if(this.includeUndocumentedUnderscored){
124 			args.add( "-A" );
125 		}
126 		if(this.includePrivate){
127 			args.add( "-p" );
128 		}
129 		args.add("-d=" + this.getOutputDirectory());
130 		String targetTemplate = this.template.indexOf(File.separator) != -1 ? this.template
131 				: this.jsdocHome + "/templates/" + this.template;
132 		args.add("-t=" + targetTemplate);
133 		// add files argument
134 		Set jsfiles = this.getJavaScriptFiles();
135 		for(Iterator iter = jsfiles.iterator(); iter.hasNext();){
136 			args.add(((File) iter.next()).getAbsolutePath());
137 		}
138 		if(this.jArgument){
139 			// tell run.js where it actually is
140 			args.add("-j=" + runJsPath);
141 		}
142 		getLog().debug("Executing: '" + args.toString().replaceAll(",","") + "'");
143 		
144 		// tell Rhino to run JSDoc with the provided params
145 		// without calling System.exit
146 		Main.exec(args.toArray(new String[0]));
147 		// restore old system property (again, not sure if our change had any
148 		// effect outside the context VM)
149 		if (systemJsdocDir != null) {
150 			System.setProperty("jsdoc.dir", systemJsdocDir);
151 			getLog().debug("Switched the system's 'sdoc.dir' property back to original value: "+System.getProperty("jsdoc.dir"));
152 		}
153 		// fix .htm/.html
154 		try {
155 			File in = new File(this.getOutputDirectory() + "/" + "index.htm");
156 			if (in.exists()) {
157 				File out = new File(this.getOutputDirectory() + "/"
158 						+ "index.html");
159 				FileChannel sourceChannel = new FileInputStream(in)
160 						.getChannel();
161 				FileChannel destinationChannel = new FileOutputStream(out)
162 						.getChannel();
163 				sourceChannel.transferTo(0, sourceChannel.size(),
164 						destinationChannel);
165 				sourceChannel.close();
166 				destinationChannel.close();
167 			}
168 		} catch (IOException e) {
169 			throw new MavenReportException("Could not copy file");
170 		}
171 		// fix
172 	}
173 
174 	/***
175 	 * Setup the plugin's internal JSDoc Toolkit version if no other is provided
176 	 * 
177 	 * @param defaultLocale
178 	 * @throws MavenReportException
179 	 */
180 	protected void setUp(Locale defaultLocale) throws MavenReportException {
181 		if (this.jsdocHome == null || this.jsdocHome.trim().length() == 0) {
182 			String jsdocDistFilename = this.getBundle(defaultLocale).getString(
183 					"jsdoc.dist.filename");
184 			this.jsdocHome = this.buildDir + "/jsdoc_run/" + jsdocDistFilename;
185 			String jsDocJar = this.baseDir + "/target/" + jsdocDistFilename
186 					+ ".zip";
187 			// copy the internal jsdoc distribution archive to target/
188 			try {
189 				InputStream input = this.getClass().getResourceAsStream(
190 						"/" + jsdocDistFilename + ".zip");
191 				OutputStream output = new FileOutputStream(jsDocJar);
192 				IOUtils.copy(input, output);
193 				input.close();
194 				output.close();
195 			} catch (FileNotFoundException fe) {
196 				throw new MavenReportException("Cannot find "
197 						+ jsdocDistFilename + ".zip" + " in classpath", fe);
198 			} catch (IOException ioe) {
199 				throw new MavenReportException("Error copying "
200 						+ jsdocDistFilename + ".zip" + " to target dir", ioe);
201 			}
202 			// unpack the jsdoc distribution archive
203 			File jarFile = new File(jsDocJar);
204 			try {
205 				UnArchiver unArchiver = this.archiverManager
206 						.getUnArchiver(jarFile);
207 				unArchiver.setSourceFile(jarFile);
208 				File destDir = new File(this.jsdocHome).getParentFile();
209 				destDir.mkdirs();
210 				unArchiver.setDestDirectory(destDir);
211 				unArchiver.extract();
212 			} catch (NoSuchArchiverException ae) {
213 				throw new MavenReportException("Unknown archiver type", ae);
214 			} catch (ArchiverException ae) {
215 				throw new MavenReportException("Error unpacking " + jarFile
216 						+ ": " + ae.toString(), ae);
217 			}
218 		}
219 	}
220 
221 	/***
222 	 * @see org.apache.maven.reporting.AbstractMavenReport#isExternalReport()
223 	 */
224 	public boolean isExternalReport() {
225 		return true;
226 	}
227 
228 	/***
229 	 * @see gr.abiss.mvn.plugins.jstools.AbstractBaseJstoolsReport#getBundleKey()
230 	 */
231 	public String getBundleKey() {
232 		return "jsdoc";
233 	}
234 
235 	/***
236 	 * Does nothing
237 	 * 
238 	 * @see gr.abiss.mvn.plugins.jstools.AbstractBaseJstoolsReport#tearDown(java.util.Locale)
239 	 */
240 	protected void tearDown(Locale defaultLocale) throws MavenReportException {
241 		try {
242 			File runDir = new File(this.buildDir + "/jsdoc_run/");
243 			if (runDir.exists()) {
244 				FileSystemDirectoryUtils.deleteDirectory(runDir);
245 			}
246 			File jsdocJar = new File(this.baseDir
247 					+ "/target/"
248 					+ this.getBundle(defaultLocale).getString(
249 							"jsdoc.dist.filename") + ".zip");
250 			if(jsdocJar.exists()){
251 				jsdocJar.delete();
252 			}
253 		} catch (Exception ioe) {
254 			throw new MavenReportException("Error clearing up", ioe);
255 		}
256 	}
257 }