| /******************************************************************************* |
| * Copyright (c) 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.api.violation; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import javax.xml.parsers.ParserConfigurationException; |
| 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.jdt.core.Signature; |
| import org.eclipse.jdt.core.util.IModifierConstants; |
| 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.ComponentAPIEmitter; |
| import org.eclipse.wtp.releng.tools.component.api.FieldAPI; |
| 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.ComponentEntry; |
| import org.eclipse.wtp.releng.tools.component.internal.ComponentSummary; |
| import org.eclipse.wtp.releng.tools.component.internal.FileLocation; |
| 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.Type; |
| import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser; |
| import org.xml.sax.SAXException; |
| |
| public class ComponentAPIViolationEmitter extends AbstractEmitter |
| { |
| private List compXMLDirs; |
| private List compXMLRefDirs; |
| private List eclipseDirs; |
| private List includes; |
| private List excludes; |
| private String outputDir; |
| private Map compLoc2CompXML; |
| private Map compLoc2CompRef; |
| private Map pluginId2Plugin; |
| private Map fragmentId2Fragment; |
| |
| public ComponentAPIViolationEmitter(List compXMLDirs, List compXMLRefDirs, List eclipseDirs, List includes, List excludes, String outputDir) |
| { |
| this.compXMLDirs = compXMLDirs; |
| this.compXMLRefDirs = compXMLRefDirs; |
| this.eclipseDirs = eclipseDirs; |
| this.includes = includes; |
| this.excludes = excludes; |
| this.outputDir = addTrailingSeperator(outputDir); |
| } |
| |
| public void genAPIViolations() throws ParserConfigurationException, SAXException, IOException, TransformerConfigurationException, TransformerException |
| { |
| compLoc2CompXML = new HashMap(); |
| compLoc2CompRef = new HashMap(); |
| pluginId2Plugin = new HashMap(); |
| fragmentId2Fragment = new HashMap(); |
| for (Iterator it = eclipseDirs.iterator(); it.hasNext();) |
| { |
| File eclipseFile = new File(addTrailingSeperator((String)it.next())); |
| if (eclipseFile.exists()) |
| harvestPlugins(eclipseFile, pluginId2Plugin, fragmentId2Fragment); |
| } |
| linkPluginsAndFragments(pluginId2Plugin, fragmentId2Fragment); |
| for (Iterator it = compXMLDirs.iterator(); it.hasNext();) |
| { |
| File compXMLFile = new File(addTrailingSeperator((String)it.next())); |
| if (compXMLFile.exists()) |
| harvestComponents(compXMLFile, compLoc2CompXML); |
| } |
| compLoc2CompRef.putAll(compLoc2CompXML); |
| if (compXMLRefDirs != null) |
| { |
| for (Iterator it = compXMLRefDirs.iterator(); it.hasNext();) |
| { |
| File compXMLRefFile = new File(addTrailingSeperator((String)it.next())); |
| if (compXMLRefFile.exists()) |
| harvestComponents(compXMLRefFile, compLoc2CompRef); |
| } |
| } |
| ComponentSummary summary = new ComponentSummary(); |
| for (Iterator it = compLoc2CompXML.keySet().iterator(); it.hasNext();) |
| { |
| String compLoc = (String)it.next(); |
| ComponentAPIEmitter compAPIEmitter = new ComponentAPIEmitter(null); |
| compAPIEmitter.init(compLoc2CompXML, pluginId2Plugin, fragmentId2Fragment); |
| ComponentAPI compAPI = compAPIEmitter.genComponentApiXml(compLoc); |
| ComponentAPIViolation v = genAPIViolation(compAPI); |
| String compName = compAPI.getName(); |
| StringBuffer sb = new StringBuffer(outputDir); |
| sb.append(compName); |
| sb.append("/component-api-violation.xml"); |
| File file = new File(sb.toString()); |
| file.getParentFile().mkdirs(); |
| FileOutputStream fos = new FileOutputStream(file); |
| fos.write(v.toString().getBytes()); |
| fos.close(); |
| ComponentEntry entry = new ComponentEntry(); |
| entry.setCompName(compName); |
| sb = new StringBuffer("./"); |
| sb.append(compName); |
| sb.append("/component-api-violation.xml"); |
| entry.setRef(sb.toString()); |
| summary.add(entry); |
| } |
| summary.save(new FileLocation(new File(outputDir + "component-api-violation-all.xml"))); |
| xslt(summary.toString(), "org/eclipse/wtp/releng/tools/component/xsl/component-api-violation.xsl", outputDir + "component-api-violation-all.html"); |
| } |
| |
| private void xslt(String content, String xsl, String output) throws SAXException, ParserConfigurationException, TransformerConfigurationException, TransformerException, FileNotFoundException |
| { |
| File outputFile = new File(output); |
| outputFile.getParentFile().mkdirs(); |
| xslt(new ByteArrayInputStream(content.getBytes()), xsl, new FileOutputStream(outputFile)); |
| } |
| |
| private void xslt(InputStream is, String xsl, OutputStream os) throws SAXException, ParserConfigurationException, TransformerConfigurationException, TransformerException, FileNotFoundException |
| { |
| String user_dir = "user.dir"; |
| String currUserDir = System.getProperty(user_dir); |
| System.setProperty(user_dir, outputDir); |
| TransformerFactory factory = TransformerFactory.newInstance(); |
| Transformer transformer = factory.newTransformer(new StreamSource(ClassLoader.getSystemResourceAsStream(xsl))); |
| transformer.transform(new StreamSource(is), new StreamResult(os)); |
| System.setProperty(user_dir, currUserDir); |
| } |
| |
| private ComponentAPIViolation genAPIViolation(ComponentAPI compAPI) |
| { |
| ComponentAPIViolation v = new ComponentAPIViolation(); |
| v.setName(compAPI.getName()); |
| for (Iterator it = compAPI.getPackageAPIs().iterator(); it.hasNext();) |
| v.addAllViolations(genAPIViolation((PackageAPI)it.next())); |
| return v; |
| } |
| |
| private List genAPIViolation(PackageAPI pkgAPI) |
| { |
| List classViolations = new ArrayList(); |
| for (Iterator it = pkgAPI.getClassAPIs().iterator(); it.hasNext();) |
| { |
| ClassViolation classViolation = genAPIViolation((ClassAPI)it.next()); |
| if (classViolation != null) |
| classViolations.add(classViolation); |
| } |
| return classViolations; |
| } |
| |
| private ClassViolation genAPIViolation(ClassAPI classAPI) |
| { |
| ClassViolation classViolation = new ClassViolation(); |
| classViolation.setName(classAPI.getName()); |
| boolean isSuperClassAPI; |
| String superClassName = classAPI.getSuperClass(); |
| if (checkAccess(classAPI.getAccess(), IModifierConstants.ACC_INTERFACE)) |
| isSuperClassAPI = isAPI(superClassName, false, false, true, false); |
| else |
| isSuperClassAPI = isAPI(superClassName, false, true, false, false); |
| if (!isSuperClassAPI) |
| { |
| SuperViolation superViolation = new SuperViolation(); |
| superViolation.setName(superClassName); |
| classViolation.addViolation(superViolation); |
| } |
| for (Iterator it = classAPI.getMethodAPIs().iterator(); it.hasNext();) |
| { |
| MethodAPI methodAPI = (MethodAPI)it.next(); |
| MethodViolation methodViolation = new MethodViolation(); |
| methodViolation.setName(methodAPI.getName()); |
| String desc = methodAPI.getDescriptor(); |
| String returnTypeDesc = Signature.getReturnType(desc); |
| String returnType = toFullyQualifiedName(returnTypeDesc); |
| if (Signature.getTypeSignatureKind(returnTypeDesc) != Signature.BASE_TYPE_SIGNATURE && !isAPI(returnType, true, false, false, false)) |
| { |
| ReturnViolation returnViolation = new ReturnViolation(); |
| returnViolation.setName(returnType); |
| methodViolation.addViolation(returnViolation); |
| } |
| String[] params = Signature.getParameterTypes(desc); |
| for (int j = 0; j < params.length; j++) |
| { |
| String param = toFullyQualifiedName(params[j]); |
| if (Signature.getTypeSignatureKind(params[j]) != Signature.BASE_TYPE_SIGNATURE && !isAPI(param, true, false, false, false)) |
| { |
| ParamViolation paramViolation = new ParamViolation(); |
| paramViolation.setName(param); |
| methodViolation.addViolation(paramViolation); |
| } |
| } |
| String[] throwTypes = Signature.getThrownExceptionTypes(desc); |
| for (int j = 0; j < throwTypes.length; j++) |
| { |
| String throwType = toFullyQualifiedName(throwTypes[j]); |
| if (Signature.getTypeSignatureKind(throwTypes[j]) != Signature.BASE_TYPE_SIGNATURE && !isAPI(throwType, true, false, false, false)) |
| { |
| ThrowViolation throwViolation = new ThrowViolation(); |
| throwViolation.setName(throwType); |
| methodViolation.addViolation(throwViolation); |
| } |
| } |
| if (methodViolation.countViolations() > 0) |
| classViolation.addViolation(methodViolation); |
| } |
| for (Iterator it = classAPI.getFieldAPIs().iterator(); it.hasNext();) |
| { |
| FieldAPI fieldAPI = (FieldAPI)it.next(); |
| String desc = new String(fieldAPI.getDescriptor()); |
| String field = toFullyQualifiedName(desc); |
| if (Signature.getTypeSignatureKind(desc) != Signature.BASE_TYPE_SIGNATURE && !isAPI(field, true, false, false, false)) |
| { |
| FieldViolation fieldViolation = new FieldViolation(); |
| fieldViolation.setName(fieldAPI.getName()); |
| fieldViolation.setType(field); |
| classViolation.addViolation(fieldViolation); |
| } |
| } |
| if (classViolation.countViolations() > 0) |
| return classViolation; |
| else |
| return null; |
| } |
| |
| private String toFullyQualifiedName(String descriptor) |
| { |
| StringBuffer sb = new StringBuffer(); |
| descriptor = descriptor.replace('/', '.'); |
| sb.append(Signature.getSignatureQualifier(descriptor)); |
| sb.append('.'); |
| sb.append(Signature.getSignatureSimpleName(descriptor).replace('.', '$')); |
| return sb.toString(); |
| } |
| |
| private boolean checkAccess(int flag, int bit) |
| { |
| return ((flag & bit) == bit); |
| } |
| |
| private boolean isAPI(String className, boolean ref, boolean subclass, boolean implement, boolean instantiate) |
| { |
| if (include(className)) |
| { |
| String pkgName = null; |
| String typeName = null; |
| int dot = className.lastIndexOf('.'); |
| if (dot != -1) |
| { |
| pkgName = className.substring(0, dot); |
| typeName = className.substring(dot + 1); |
| } |
| if (pkgName != null && typeName != null) |
| { |
| for (Iterator it = compLoc2CompRef.values().iterator(); it.hasNext();) |
| { |
| ComponentXML compXML = (ComponentXML)it.next(); |
| for (Iterator pkgIt = compXML.getPackages().iterator(); pkgIt.hasNext();) |
| { |
| Package pkg = (Package)pkgIt.next(); |
| if (pkgName.equals(pkg.getName())) |
| { |
| // if not overwritten, inner class inherits usages from base class |
| int index = typeName.indexOf('$'); |
| String baseTypeName = (index != -1) ? typeName.substring(0, index) : null; |
| Type baseType = null; |
| for (Iterator typeIt = pkg.getTypes().iterator(); typeIt.hasNext();) |
| { |
| Type type = (Type)typeIt.next(); |
| String name = type.getName(); |
| if (typeName.equals(name)) |
| { |
| if (ref && !type.isReference()) |
| return false; |
| if (subclass && !type.isSubclass()) |
| return false; |
| if (implement && !type.isImplement()) |
| return false; |
| if (instantiate && !type.isInstantiate()) |
| return false; |
| return true; |
| } |
| if (baseTypeName != null && baseType == null && baseTypeName.equals(name)) |
| { |
| baseType = type; |
| } |
| } |
| if (baseType != null) |
| { |
| if (ref && !baseType.isReference()) |
| return false; |
| if (subclass && !baseType.isSubclass()) |
| return false; |
| if (implement && !baseType.isImplement()) |
| return false; |
| if (instantiate && !baseType.isInstantiate()) |
| return false; |
| return true; |
| } |
| return pkg.isApi(); |
| } |
| } |
| } |
| } |
| return false; |
| } |
| else |
| { |
| return true; |
| } |
| } |
| |
| private boolean include(String className) |
| { |
| if (excludes != null) |
| for (Iterator it = excludes.iterator(); it.hasNext();) |
| if (className.startsWith((String)it.next())) |
| return false; |
| if (includes != null && includes.size() > 0) |
| { |
| for (Iterator it = includes.iterator(); it.hasNext();) |
| if (className.startsWith((String)it.next())) |
| return true; |
| return false; |
| } |
| return true; |
| } |
| |
| public static void main(String[] args) |
| { |
| CommandOptionParser optionParser = new CommandOptionParser(args); |
| Map options = optionParser.getOptions(); |
| List compXMLDirs = (List)options.get("compXMLDirs"); |
| List compXMLRefDirs = (List)options.get("compXMLRefDirs"); |
| List eclipseDirs = (List)options.get("eclipseDirs"); |
| List outputDir = (List)options.get("outputDir"); |
| List includes = (List)options.get("includes"); |
| List excludes = (List)options.get("excludes"); |
| if (compXMLDirs == null || eclipseDirs == null || outputDir == null || compXMLDirs.size() < 1 || eclipseDirs.size() < 1 || outputDir.size() < 1) |
| { |
| printUsage(); |
| System.exit(-1); |
| } |
| ComponentAPIViolationEmitter emitter = new ComponentAPIViolationEmitter(compXMLDirs, compXMLRefDirs, eclipseDirs, includes, excludes, (String)outputDir.get(0)); |
| try |
| { |
| emitter.genAPIViolations(); |
| } |
| catch (Throwable t) |
| { |
| t.printStackTrace(); |
| } |
| } |
| |
| private static void printUsage() |
| { |
| System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.api.violation.APIViolationEmitter -compXMLDirs <compXMLDirs> -eclipseDirs <eclipseDirs> -outputDir <outputDir> [-options]"); |
| System.out.println(""); |
| System.out.println("\t-compXMLDirs\t<compXMLDirs>\tspace seperated list of directories containing component.xml files"); |
| System.out.println("\t-eclipseDirs\t<eclipseDirs>\tspace seperated list of directories containing Eclipse plugins"); |
| System.out.println("\t-outputDir\t<outputDir>\toutput directory"); |
| System.out.println(""); |
| System.out.println("where options include:"); |
| System.out.println(""); |
| System.out.println("\t-compXMLRefDirs\t<compXMLRefDirs>\tspace seperated list of directories containing component.xml files being referenced"); |
| System.out.println("\t-includes\t<includes>\tpackages to include"); |
| System.out.println("\t-excludes\t<excludes>\tpackages to exclude"); |
| } |
| } |