| /******************************************************************************* |
| * Copyright (c) 2004, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.wtp.releng.tools.component.javadoc; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.stream.StreamResult; |
| import javax.xml.transform.stream.StreamSource; |
| import org.eclipse.core.runtime.IPlatformRunnable; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTParser; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.Javadoc; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.MethodRef; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.PrimitiveType; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.TagElement; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.internal.core.util.CharArrayBuffer; |
| import org.eclipse.wtp.releng.tools.component.IFileLocation; |
| import org.eclipse.wtp.releng.tools.component.ILocation; |
| import org.eclipse.wtp.releng.tools.component.api.ClassAPI; |
| import org.eclipse.wtp.releng.tools.component.api.ComponentAPI; |
| import org.eclipse.wtp.releng.tools.component.api.FieldAPI; |
| import org.eclipse.wtp.releng.tools.component.api.JavadocCoverage; |
| import org.eclipse.wtp.releng.tools.component.api.MethodAPI; |
| import org.eclipse.wtp.releng.tools.component.api.PackageAPI; |
| import org.eclipse.wtp.releng.tools.component.internal.AbstractEmitter; |
| import org.eclipse.wtp.releng.tools.component.internal.FileLocation; |
| import org.eclipse.wtp.releng.tools.component.internal.PluginClasspath; |
| import org.eclipse.wtp.releng.tools.component.model.ComponentXML; |
| import org.eclipse.wtp.releng.tools.component.model.Package; |
| import org.eclipse.wtp.releng.tools.component.model.Plugin; |
| import org.eclipse.wtp.releng.tools.component.model.Type; |
| |
| public class JavadocCoverageEmitter extends AbstractEmitter implements IPlatformRunnable |
| { |
| private ASTParser parser = ASTParser.newParser(AST.JLS2); |
| |
| public Object run(Object arguments) |
| { |
| try |
| { |
| String compXMLDir = addTrailingSeperator(System.getProperty("compXMLDir")); |
| String compAPIDir = addTrailingSeperator(System.getProperty("compAPIDir")); |
| String srcDir = addTrailingSeperator(System.getProperty("srcDir")); |
| String outputDir = addTrailingSeperator(System.getProperty("outputDir")); |
| if (compXMLDir != null && srcDir != null && outputDir != null) |
| { |
| Map compName2CompXML = new HashMap(); |
| harvestComponents(new File(compXMLDir), compName2CompXML); |
| List compAPIs = new ArrayList(); |
| harvestComponentAPIs(new File(compAPIDir), compAPIs); |
| Map id2Plugin = new HashMap(); |
| Map id2Fragment = new HashMap(); |
| harvestPlugins(new File(srcDir), id2Plugin, id2Fragment); |
| linkPluginsAndFragments(id2Plugin, id2Fragment); |
| JavadocCoverageSummary summary = new JavadocCoverageSummary(); |
| for (Iterator it = compAPIs.iterator(); it.hasNext();) |
| { |
| ComponentAPI compAPI = (ComponentAPI)it.next(); |
| compAPI.load(); |
| genJavadocCoverageXML(compAPI, (ComponentXML)compName2CompXML.get(compAPI.getName()), id2Plugin, outputDir); |
| summary.add(compAPI); |
| } |
| summary.save(new FileLocation(new File(outputDir + "index-api-javadoc.xml"))); |
| summary.saveAsHTML("org/eclipse/wtp/releng/tools/component/xsl/component-api-javadoc-summary.xsl", new FileLocation(new File(outputDir + "index-api-javadoc.html"))); |
| } |
| } |
| catch (Throwable t) |
| { |
| t.printStackTrace(); |
| } |
| return IPlatformRunnable.EXIT_OK; |
| } |
| |
| protected void harvestComponents(File file, Map compName2CompXML) |
| { |
| if (file.isDirectory()) |
| { |
| File[] files = file.listFiles(); |
| for (int i = 0; i < files.length; i++) |
| harvestComponents(files[i], compName2CompXML); |
| } |
| else if (ComponentXML.CONST_COMPONENT_XML.equalsIgnoreCase(file.getName())) |
| { |
| ComponentXML compXML = new ComponentXML(); |
| ILocation location = new FileLocation(file); |
| compXML.setLocation(location); |
| try |
| { |
| compXML.load(); |
| compName2CompXML.put(compXML.getName(), compXML); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| protected void harvestComponentAPIs(File file, List compAPIs) |
| { |
| if (file.isDirectory()) |
| { |
| File[] files = file.listFiles(); |
| for (int i = 0; i < files.length; i++) |
| harvestComponentAPIs(files[i], compAPIs); |
| } |
| else if (ComponentAPI.CONST_COMPONENT_API.equalsIgnoreCase(file.getName())) |
| { |
| ComponentAPI compAPI = new ComponentAPI(); |
| ILocation location = new FileLocation(file); |
| compAPI.setLocation(location); |
| compAPIs.add(compAPI); |
| } |
| } |
| |
| public PluginClasspath getPluginClasspath(IFileLocation fileLocation, boolean validate) |
| { |
| return super.getPluginClasspath(fileLocation, false); |
| } |
| |
| private void genJavadocCoverageXML(ComponentAPI compAPI, ComponentXML compXML, Map id2Plugin, String outputDir) throws IOException, TransformerConfigurationException, TransformerException |
| { |
| for (Iterator it = compXML.getPlugins().iterator(); it.hasNext();) |
| { |
| Plugin plugin = (Plugin)it.next(); |
| Object object = id2Plugin.get(plugin.getId()); |
| if (object instanceof PluginClasspath) |
| { |
| PluginClasspath pluginCp = (PluginClasspath)object; |
| for (Iterator pkgsIt = compXML.getPackages().iterator(); pkgsIt.hasNext();) |
| { |
| genJavadocCoverageXML(compAPI, (Package)pkgsIt.next(), addTrailingSeperator(pluginCp.getDotClasspathLocation().getFile().getParentFile().getAbsolutePath()), pluginCp.getSrcPaths()); |
| } |
| } |
| } |
| compAPI.save(); |
| StringBuffer sb = new StringBuffer(outputDir); |
| sb.append(compAPI.getName()); |
| sb.append("/component-api-javadoc.html"); |
| TransformerFactory factory = TransformerFactory.newInstance(); |
| Transformer transformer = factory.newTransformer(new StreamSource(Platform.getBundle("org.eclipse.wtp.releng.tools.component.core").getResource("org/eclipse/wtp/releng/tools/component/xsl/component-api-javadoc.xsl").openStream())); |
| transformer.transform(new StreamSource(new ByteArrayInputStream(compAPI.toString().getBytes())), new StreamResult(new FileOutputStream(new File(sb.toString())))); |
| } |
| |
| private void genJavadocCoverageXML(ComponentAPI compAPI, Package pkg, String baseDir, List srcPaths) throws IOException |
| { |
| String pkgName = pkg.getName(); |
| String pkgDir = pkgName.replace('.', '/'); |
| PackageAPI pkgAPI = null; |
| for (Iterator pkgIt = compAPI.getPackageAPIs().iterator(); pkgIt.hasNext();) |
| { |
| PackageAPI p = (PackageAPI)pkgIt.next(); |
| if (pkgName.equals(p.getName())) |
| { |
| pkgAPI = p; |
| break; |
| } |
| } |
| if (pkgAPI != null) |
| { |
| if (pkg.isApi()) |
| { |
| List excludes = new ArrayList(); |
| Collection types = pkg.getTypes(); |
| for (Iterator it = types.iterator(); it.hasNext();) |
| { |
| Type type = (Type)it.next(); |
| if (!type.isImplement() && !type.isInstantiate() && !type.isReference() && !type.isSubclass()) |
| excludes.add(type.getName() + ".java"); |
| } |
| for (Iterator it = srcPaths.iterator(); it.hasNext();) |
| { |
| StringBuffer sb = new StringBuffer(baseDir); |
| sb.append((String)it.next()); |
| sb.append('/'); |
| sb.append(pkgDir); |
| genJavadocCoverageXML(pkgAPI, new File(sb.toString()), excludes); |
| } |
| } |
| else |
| { |
| Collection types = pkg.getTypes(); |
| for (Iterator it = types.iterator(); it.hasNext();) |
| { |
| Type type = (Type)it.next(); |
| if (type.isImplement() || type.isInstantiate() || type.isReference() || type.isSubclass()) |
| { |
| for (Iterator srcIt = srcPaths.iterator(); srcIt.hasNext();) |
| { |
| String typeName = type.getName(); |
| StringBuffer sb = new StringBuffer(baseDir); |
| sb.append((String)srcIt.next()); |
| sb.append('/'); |
| sb.append(pkgDir); |
| sb.append('/'); |
| sb.append(typeName); |
| sb.append(".java"); |
| for (Iterator classIt = pkgAPI.getClassAPIs().iterator(); classIt.hasNext();) |
| { |
| ClassAPI classAPI = (ClassAPI)classIt.next(); |
| if (typeName.equals(classAPI.getName())) |
| { |
| genJavadocCoverageXML(classAPI, new File(sb.toString())); |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private void genJavadocCoverageXML(PackageAPI pkgAPI, File dir, List excludes) throws IOException |
| { |
| if (dir.exists() && dir.isDirectory()) |
| { |
| String pkgName = pkgAPI.getName(); |
| File[] children = dir.listFiles(); |
| for (int i = 0; i < children.length; i++) |
| { |
| if (children[i].isFile()) |
| { |
| String fileName = children[i].getName(); |
| if (fileName.endsWith(".java") && (excludes == null || !excludes.contains(fileName))) |
| { |
| StringBuffer qualifiedName = new StringBuffer(pkgName); |
| qualifiedName.append('.'); |
| qualifiedName.append(fileName.substring(0, fileName.length() - 5)); |
| for (Iterator it = pkgAPI.getClassAPIs().iterator(); it.hasNext();) |
| { |
| ClassAPI classAPI = (ClassAPI)it.next(); |
| if (qualifiedName.toString().equals(classAPI.getName())) |
| { |
| genJavadocCoverageXML(classAPI, children[i]); |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| private void genJavadocCoverageXML(ClassAPI classAPI, File javaFile) throws IOException |
| { |
| FileReader fr = new FileReader(javaFile); |
| CharArrayBuffer cab = new CharArrayBuffer(); |
| char[] c = new char[2048]; |
| for (int read = fr.read(c); read != -1; read = fr.read(c)) |
| cab.append(c, 0, read); |
| fr.close(); |
| parser.setSource(cab.getContents()); |
| ASTNode node = parser.createAST(null); |
| JavadocVisitor visitor = new JavadocVisitor(classAPI); |
| node.accept(visitor); |
| } |
| |
| private class JavadocVisitor extends ASTVisitor |
| { |
| private ClassAPI classAPI; |
| |
| public JavadocVisitor(ClassAPI classAPI) |
| { |
| this.classAPI = classAPI; |
| } |
| |
| public boolean visit(TypeDeclaration node) |
| { |
| if (!checkModifier(node.getModifiers(), Modifier.PRIVATE)) |
| { |
| Javadoc javadoc = node.getJavadoc(); |
| if (javadoc != null) |
| { |
| List tags = javadoc.tags(); |
| for (Iterator it = tags.iterator(); it.hasNext();) |
| { |
| TagElement tag = (TagElement)it.next(); |
| String tagName = tag.getTagName(); |
| if (tagName != null && tagName.equals(TagElement.TAG_SINCE)) |
| { |
| return true; |
| } |
| } |
| } |
| classAPI.getJavadocCoverage().setHasSince(Boolean.FALSE); |
| } |
| return true; |
| } |
| |
| public boolean visit(MethodDeclaration node) |
| { |
| String methodName = node.getName().getFullyQualifiedName(); |
| if (classAPI.getName().endsWith("." + methodName)) |
| methodName = "<init>"; |
| MethodAPI methodAPI = null; |
| for (Iterator it = classAPI.getMethodAPIs().iterator(); it.hasNext();) |
| { |
| MethodAPI m = (MethodAPI)it.next(); |
| if (methodName.equals(m.getName()) && !m.isSetJavadocCoverage()) |
| { |
| methodAPI = m; |
| break; |
| } |
| } |
| if (methodAPI != null && !checkModifier(node.getModifiers(), Modifier.PRIVATE)) |
| { |
| boolean hasReturn = false; |
| org.eclipse.jdt.core.dom.Type returnType = node.getReturnType(); |
| if (returnType instanceof PrimitiveType) |
| if (((PrimitiveType)returnType).getPrimitiveTypeCode() == PrimitiveType.VOID) |
| hasReturn = true; |
| List paramList = new ArrayList(); |
| List params = node.parameters(); |
| for (Iterator it = params.iterator(); it.hasNext();) |
| { |
| SingleVariableDeclaration param = (SingleVariableDeclaration)it.next(); |
| SimpleName simpleName = param.getName(); |
| paramList.add(simpleName.getIdentifier()); |
| } |
| List throwList = new ArrayList(); |
| List thrownExceptions = node.thrownExceptions(); |
| for (Iterator it = thrownExceptions.iterator(); it.hasNext();) |
| { |
| Name name = (Name)it.next(); |
| throwList.add(name.getFullyQualifiedName()); |
| } |
| boolean hasDoc = false; |
| Javadoc javadoc = node.getJavadoc(); |
| if (javadoc != null) |
| { |
| hasDoc = true; |
| List tags = javadoc.tags(); |
| for (Iterator it = tags.iterator(); it.hasNext();) |
| { |
| TagElement tag = (TagElement)it.next(); |
| String tagName = tag.getTagName(); |
| if (tagName != null) |
| { |
| if (tagName.equals(TagElement.TAG_RETURN)) |
| hasReturn = tag.fragments().size() > 0; |
| else if (tagName.equals(TagElement.TAG_PARAM)) |
| { |
| List fragments = tag.fragments(); |
| if (fragments.size() > 1) |
| { |
| Object fragment = fragments.get(0); |
| if (fragment instanceof SimpleName) |
| { |
| paramList.remove(((SimpleName)fragment).getIdentifier()); |
| } |
| } |
| } |
| else if (tagName.equals(TagElement.TAG_THROWS) || tagName.equals(TagElement.TAG_EXCEPTION)) |
| { |
| List fragments = tag.fragments(); |
| if (fragments.size() > 1) |
| { |
| Object fragment = fragments.get(0); |
| if (fragment instanceof Name) |
| { |
| throwList.remove(((Name)fragment).getFullyQualifiedName()); |
| } |
| } |
| } |
| else if (tagName.equals(TagElement.TAG_SEE)) |
| { |
| List fragments = tag.fragments(); |
| if (fragments.size() > 0) |
| { |
| Object fragment = fragments.get(0); |
| if (fragment instanceof MethodRef) |
| { |
| MethodRef methodRef = (MethodRef)fragment; |
| if (methodName.equals(methodRef.getName().getFullyQualifiedName())) |
| { |
| return true; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| if (!hasDoc || !hasReturn || paramList.size() > 0 || throwList.size() > 0) |
| { |
| JavadocCoverage javadocCoverage = methodAPI.getJavadocCoverage(); |
| if (!hasDoc) |
| { |
| javadocCoverage.setHasDoc(Boolean.FALSE); |
| } |
| if (!hasReturn) |
| { |
| javadocCoverage.setHasReturn(Boolean.FALSE); |
| } |
| if (paramList.size() > 0) |
| { |
| for (Iterator it = paramList.iterator(); it.hasNext();) |
| { |
| javadocCoverage.addMissingParam((String)it.next()); |
| } |
| } |
| if (throwList.size() > 0) |
| { |
| for (Iterator it = throwList.iterator(); it.hasNext();) |
| { |
| javadocCoverage.addMissingThrow((String)it.next()); |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| public boolean visit(FieldDeclaration node) |
| { |
| String fieldName = null; |
| List varDeclFragments = node.fragments(); |
| for (Iterator it = varDeclFragments.iterator(); it.hasNext();) |
| { |
| VariableDeclarationFragment varDeclFragment = (VariableDeclarationFragment)it.next(); |
| fieldName = varDeclFragment.getName().getFullyQualifiedName(); |
| } |
| if (fieldName != null) |
| { |
| FieldAPI fieldAPI = null; |
| for (Iterator it = classAPI.getFieldAPIs().iterator(); it.hasNext();) |
| { |
| FieldAPI f = (FieldAPI)it.next(); |
| if (fieldName.equals(f.getName()) && !f.isSetJavadocCoverage()) |
| { |
| fieldAPI = f; |
| break; |
| } |
| } |
| if (fieldAPI != null && !checkModifier(node.getModifiers(), Modifier.PRIVATE)) |
| { |
| Javadoc javadoc = node.getJavadoc(); |
| if (javadoc == null) |
| { |
| fieldAPI.setJavadocCoverage(new JavadocCoverage()); |
| } |
| } |
| } |
| return true; |
| } |
| |
| private boolean checkModifier(int modifier, int bit) |
| { |
| return ((modifier & bit) == bit); |
| } |
| } |
| } |