| /******************************************************************************* |
| * 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.violation; |
| |
| import java.io.File; |
| 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.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import org.eclipse.wtp.releng.tools.component.IClazz; |
| import org.eclipse.wtp.releng.tools.component.ILibrary; |
| import org.eclipse.wtp.releng.tools.component.ILocation; |
| import org.eclipse.wtp.releng.tools.component.IPluginXML; |
| 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.model.ComponentDepends; |
| import org.eclipse.wtp.releng.tools.component.model.ComponentRef; |
| 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; |
| import org.eclipse.wtp.releng.tools.component.use.ClassUse; |
| import org.eclipse.wtp.releng.tools.component.use.ComponentUse; |
| import org.eclipse.wtp.releng.tools.component.use.ComponentUseEmitter; |
| import org.eclipse.wtp.releng.tools.component.use.Source; |
| import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser; |
| |
| public class ComponentViolationEmitter extends AbstractEmitter |
| { |
| public static final String CONST_COMPONENT_VIOLATION_XML = "component-violation.xml"; |
| public static final String CONST_COMPONENT_VIOLATION_HTML = "component-violation.html"; |
| public static final String OPTION_ECLIPSE_DIR = "eclipseDir"; |
| public static final String OPTION_COMPONENT_XML_DIR = "compXMLDir"; |
| public static final String OPTION_COMPONENT_REF_DIR = "compRefDir"; |
| public static final String OPTION_COMPONENT_VIOLATION_DIR = "compVioDir"; |
| public static final String OPTION_INCLUDE = "include"; |
| public static final String OPTION_EXCLUDE = "exclude"; |
| public static final String OPTION_GEN_HTML = "genHTML"; |
| public static final String OPTION_GEN_USAGE = "genUsage"; |
| public static final String OPTION_DEBUG = "debug"; |
| |
| private String compViolationDir; |
| private Map pluginId2Plugin; |
| private Map fragmentId2Fragment; |
| private Map compLoc2CompXML; |
| private Map compLoc2CompRef; |
| private List classUseIncludes; |
| private List classUseIncludesMatch; |
| private List classUseExcludes; |
| private List classUseExcludesMatch; |
| private boolean genHTML; |
| private boolean genUsage; |
| private boolean classRefOnly; |
| private boolean debug; |
| private ComponentUseEmitter compUseEmitter; |
| |
| public ComponentViolationEmitter(String compViolationDir) |
| { |
| this.compViolationDir = addTrailingSeperator(compViolationDir); |
| genUsage = false; |
| classRefOnly = false; |
| debug = false; |
| } |
| |
| public void init(List eclipseDirs, List compXMLDirs, List compRefDirs) |
| { |
| 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); |
| } |
| if (compRefDirs != null) |
| { |
| for (Iterator it = compRefDirs.iterator(); it.hasNext();) |
| { |
| File compRefFile = new File(addTrailingSeperator((String)it.next())); |
| if (compRefFile.exists()) |
| harvestComponents(compRefFile, compLoc2CompRef); |
| } |
| } |
| init(); |
| } |
| |
| public void init(Map compLoc2CompXML, Map compLoc2CompRef, Map pluginId2Plugin, Map fragmentId2Fragment) |
| { |
| this.compLoc2CompXML = compLoc2CompXML; |
| this.compLoc2CompRef = compLoc2CompRef; |
| this.pluginId2Plugin = pluginId2Plugin; |
| this.fragmentId2Fragment = fragmentId2Fragment; |
| init(); |
| } |
| |
| private void init() |
| { |
| compUseEmitter = new ComponentUseEmitter(genUsage ? compViolationDir : null); |
| compUseEmitter.setClassUseIncludes(classUseIncludes); |
| compUseEmitter.setClassUseIncludesMatch(classUseIncludesMatch); |
| compUseEmitter.setClassUseExcludes(classUseExcludes); |
| compUseEmitter.setClassUseExcludesMatch(classUseExcludesMatch); |
| compUseEmitter.setClassRefOnly(classRefOnly); |
| compUseEmitter.setDebug(debug); |
| compUseEmitter.init(compLoc2CompXML, pluginId2Plugin, fragmentId2Fragment); |
| } |
| |
| public Map getCompRefs() |
| { |
| return new HashMap(compLoc2CompRef); |
| } |
| |
| public void setCompRefs(Map compLoc2CompRef) |
| { |
| this.compLoc2CompRef = compLoc2CompRef; |
| } |
| |
| public List getClassUseIncludes() |
| { |
| return classUseIncludes; |
| } |
| |
| public void setClassUseIncludes(List includes) |
| { |
| this.classUseIncludes = includes; |
| } |
| |
| public List getClassUseIncludesMatch() |
| { |
| return classUseIncludesMatch; |
| } |
| |
| public void setClassUseIncludesMatch(List includesMatch) |
| { |
| this.classUseIncludesMatch = includesMatch; |
| } |
| |
| public List getClassUseExcludes() |
| { |
| return classUseExcludes; |
| } |
| |
| public void setClassUseExcludes(List excludes) |
| { |
| this.classUseExcludes = excludes; |
| } |
| |
| public List getClassUseExcludesMatch() |
| { |
| return classUseExcludesMatch; |
| } |
| |
| public void setClassUseExcludesMatch(List excludesMatch) |
| { |
| this.classUseExcludesMatch = excludesMatch; |
| } |
| |
| /** |
| * @return Returns the genHTML. |
| */ |
| public boolean isGenHTML() |
| { |
| return genHTML; |
| } |
| |
| /** |
| * @param genHTML The genHTML to set. |
| */ |
| public void setGenHTML(boolean genHTML) |
| { |
| this.genHTML = genHTML; |
| } |
| |
| public boolean getGenUsage() |
| { |
| return genUsage; |
| } |
| |
| public void setGenUsage(boolean genUsage) |
| { |
| this.genUsage = genUsage; |
| } |
| |
| /** |
| * @return Returns the classRefOnly. |
| */ |
| public boolean isClassRefOnly() |
| { |
| return classRefOnly; |
| } |
| |
| /** |
| * @param classRefOnly |
| * The classRefOnly to set. |
| */ |
| public void setClassRefOnly(boolean classRefOnly) |
| { |
| this.classRefOnly = classRefOnly; |
| } |
| |
| /** |
| * @return Returns the debug. |
| */ |
| public boolean isDebug() |
| { |
| return debug; |
| } |
| |
| /** |
| * @param debug The debug to set. |
| */ |
| public void setDebug(boolean debug) |
| { |
| this.debug = debug; |
| } |
| |
| public void genComponentViolationXML() throws IOException |
| { |
| ComponentViolationSummary summary = new ComponentViolationSummary(); |
| for (Iterator it = compLoc2CompXML.keySet().iterator(); it.hasNext();) |
| summary.add(genComponentViolationXML((String)it.next())); |
| if (compViolationDir != null) |
| { |
| summary.save(new FileLocation(new File(compViolationDir + "index.xml"))); |
| if (genHTML) |
| { |
| try |
| { |
| summary.saveAsHTML(new FileLocation(new File(compViolationDir + "index.html"))); |
| } |
| catch (TransformerConfigurationException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (TransformerException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| public ComponentUse genComponentViolationXML(String compLoc) throws IOException |
| { |
| ComponentUse compUse = null; |
| ComponentXML componentXML = (ComponentXML)compLoc2CompXML.get(compLoc); |
| if (componentXML != null) |
| { |
| componentXML.load(); |
| compUse = compUseEmitter.genComponentUseXML(compLoc); |
| compUse.save(); |
| for (Iterator pluginsIt = componentXML.getPlugins().iterator(); pluginsIt.hasNext();) |
| { |
| IPluginXML pluginXML = (IPluginXML)pluginId2Plugin.get(((Plugin)pluginsIt.next()).getId()); |
| if (pluginXML != null) |
| validateComponentUse(pluginXML, compUse); |
| } |
| ComponentDepends depends = componentXML.getComponentDepends(); |
| boolean unrestricted = depends.isUnrestricted(); |
| List dependNames = null; |
| if (!unrestricted) |
| { |
| dependNames = new ArrayList(); |
| Collection compRefs = depends.getComponentRefs(); |
| for (Iterator it = compRefs.iterator(); it.hasNext();) |
| dependNames.add(((ComponentRef)it.next()).getName()); |
| } |
| for (Iterator it = compLoc2CompXML.values().iterator(); it.hasNext() && compUse.getSources().size() > 0;) |
| { |
| ComponentXML compXML = (ComponentXML)it.next(); |
| if (unrestricted || dependNames.contains(compXML.getName())) |
| { |
| compXML.load(); |
| validateComponentUse(compXML, compUse); |
| } |
| } |
| for (Iterator it = compLoc2CompRef.values().iterator(); it.hasNext() && compUse.getSources().size() > 0;) |
| { |
| ComponentXML compXML = (ComponentXML)it.next(); |
| if (unrestricted || dependNames.contains(compXML.getName())) |
| { |
| compXML.load(); |
| validateComponentUse(compXML, compUse); |
| } |
| } |
| if (compViolationDir != null) |
| { |
| String compName = compUse.getName(); |
| System.out.println("Writing component-violation.xml for " + compName); |
| StringBuffer sb = new StringBuffer(compViolationDir); |
| sb.append(compName); |
| sb.append('/'); |
| compUse.setLocation(new FileLocation(new File(sb.toString() + CONST_COMPONENT_VIOLATION_XML))); |
| compUse.save(); |
| if (genHTML) |
| { |
| try |
| { |
| ILocation html = new FileLocation(new File(sb.toString() + CONST_COMPONENT_VIOLATION_HTML)); |
| compUse.setLocation(html); |
| compUse.saveAsHTML(html); |
| } |
| catch (TransformerConfigurationException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (TransformerException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| return compUse; |
| } |
| |
| public Source genViolation(String compLoc, IClazz clazz) |
| { |
| Source source = null; |
| ComponentXML componentXML = (ComponentXML)compLoc2CompXML.get(compLoc); |
| if (componentXML != null) |
| { |
| boolean valid = false; |
| source = compUseEmitter.genUse(clazz); |
| for (Iterator pluginsIt = componentXML.getPlugins().iterator(); pluginsIt.hasNext();) |
| { |
| IPluginXML pluginXML = (IPluginXML)pluginId2Plugin.get(((Plugin)pluginsIt.next()).getId()); |
| if (pluginXML != null) |
| { |
| if (validateComponentUse(pluginXML, source)) |
| { |
| valid = true; |
| break; |
| } |
| } |
| } |
| ComponentDepends depends = componentXML.getComponentDepends(); |
| boolean unrestricted = depends.isUnrestricted(); |
| List dependNames = null; |
| if (!unrestricted) |
| { |
| dependNames = new ArrayList(); |
| Collection compRefs = depends.getComponentRefs(); |
| for (Iterator it = compRefs.iterator(); it.hasNext();) |
| dependNames.add(((ComponentRef)it.next()).getName()); |
| } |
| if (!valid) |
| { |
| for (Iterator it = compLoc2CompXML.values().iterator(); it.hasNext();) |
| { |
| ComponentXML comp = (ComponentXML)it.next(); |
| if (unrestricted || dependNames.contains(comp.getName())) |
| { |
| valid = validateComponentUse(comp, source); |
| if (valid) |
| break; |
| } |
| } |
| } |
| if (!valid) |
| { |
| for (Iterator it = compLoc2CompRef.values().iterator(); it.hasNext();) |
| { |
| ComponentXML comp = (ComponentXML)it.next(); |
| if (unrestricted || dependNames.contains(comp.getName())) |
| { |
| valid = validateComponentUse(comp, source); |
| if (valid) |
| break; |
| } |
| } |
| } |
| } |
| return source; |
| } |
| |
| private void validateComponentUse(IPluginXML pluginXML, ComponentUse compUse) |
| { |
| List sources = compUse.getSources(); |
| for (int i = 0; i < sources.size(); i++) |
| { |
| if (validateComponentUse(pluginXML, (Source)sources.get(i))) |
| { |
| sources.remove(i); |
| i--; |
| } |
| } |
| } |
| |
| private boolean validateComponentUse(IPluginXML pluginXML, Source source) |
| { |
| List classUses = new ArrayList(source.getClassUses()); |
| for (int j = 0; j < classUses.size(); j++) |
| { |
| ClassUse classUse = (ClassUse)classUses.get(j); |
| if (validateComponentUse(pluginXML, classUse)) |
| { |
| classUses.remove(j); |
| j--; |
| } |
| } |
| return classUses.size() == 0; |
| } |
| |
| private boolean validateComponentUse(IPluginXML pluginXML, ClassUse classUse) |
| { |
| String classUseName = classUse.getName(); |
| int dollarSign = classUseName.indexOf('$'); |
| if (dollarSign != -1) |
| classUseName = classUseName.substring(0, dollarSign); |
| List libs = pluginXML.getLibraries(); |
| for (Iterator libsIt = libs.iterator(); libsIt.hasNext();) |
| { |
| ILibrary lib = (ILibrary)libsIt.next(); |
| Map types = lib.getTypes(); |
| if (types.containsKey(classUseName)) |
| return true; |
| } |
| return false; |
| } |
| |
| private void validateComponentUse(ComponentXML compXML, ComponentUse compUse) |
| { |
| List sources = compUse.getSources(); |
| for (int i = 0; i < sources.size(); i++) |
| { |
| if (validateComponentUse(compXML, (Source)sources.get(i))) |
| { |
| sources.remove(i); |
| i--; |
| } |
| } |
| } |
| |
| private boolean validateComponentUse(ComponentXML compXML, Source source) |
| { |
| List classUses = new ArrayList(source.getClassUses()); |
| for (int j = 0; j < classUses.size(); j++) |
| { |
| ClassUse classUse = (ClassUse)classUses.get(j); |
| if (validateComponentUse(compXML, classUse)) |
| { |
| classUses.remove(j); |
| j--; |
| } |
| } |
| return classUses.size() == 0; |
| } |
| |
| private boolean validateComponentUse(ComponentXML compXML, ClassUse classUse) |
| { |
| String classUseName = classUse.getName(); |
| Collection pkgs = compXML.getPackages(); |
| for (Iterator pkgsIt = pkgs.iterator(); pkgsIt.hasNext();) |
| { |
| Package pkg = (Package)pkgsIt.next(); |
| String pkgName = pkg.getName(); |
| if (classUseName.startsWith(pkgName) && classUseName.substring(pkgName.length() + 1).indexOf('.') == -1) |
| { |
| Collection types = pkg.getTypes(); |
| for (Iterator typesIt = types.iterator(); typesIt.hasNext();) |
| { |
| Type type = (Type)typesIt.next(); |
| if (classUseName.equals(type.getName())) |
| { |
| if (!classUse.isReference() || type.isReference()) |
| if (!classUse.isSubclass() || type.isSubclass()) |
| if (!classUse.isImplement() || type.isImplement()) |
| if (!classUse.isInstantiate() || type.isInstantiate()) |
| return true; |
| return false; |
| } |
| } |
| return pkg.isApi(); |
| } |
| } |
| return false; |
| } |
| |
| public static void main(String[] args) |
| { |
| CommandOptionParser optionParser = new CommandOptionParser(args); |
| Map options = optionParser.getOptions(); |
| List eclipseDir = (List)options.get(ComponentViolationEmitter.OPTION_ECLIPSE_DIR); |
| List compXMLDir = (List)options.get(ComponentViolationEmitter.OPTION_COMPONENT_XML_DIR); |
| List compRefDir = (List)options.get(ComponentViolationEmitter.OPTION_COMPONENT_REF_DIR); |
| List compViolationDir = (List)options.get(ComponentViolationEmitter.OPTION_COMPONENT_VIOLATION_DIR); |
| List includes = (List)options.get(ComponentViolationEmitter.OPTION_INCLUDE); |
| List excludes = (List)options.get(ComponentViolationEmitter.OPTION_EXCLUDE); |
| List genHTML = (List)options.get(ComponentViolationEmitter.OPTION_GEN_HTML); |
| List genUsage = (List)options.get(ComponentViolationEmitter.OPTION_GEN_USAGE); |
| List classRefOnly = (List)options.get(ComponentUseEmitter.OPTION_CLASS_REF_ONLY); |
| List debug = (List)options.get(ComponentUseEmitter.OPTION_DEBUG); |
| if (eclipseDir == null || compXMLDir == null || compViolationDir == null || eclipseDir.size() < 1 || compXMLDir.size() < 1 || compViolationDir.size() < 1) |
| { |
| printUsage(); |
| System.exit(-1); |
| } |
| List includesStart = null; |
| List includesMatch = null; |
| if (includes != null) |
| { |
| for (Iterator it = includes.iterator(); it.hasNext();) |
| { |
| String s = (String)it.next(); |
| if (s.charAt(0) == '*' && s.charAt(s.length() - 1) == '*') |
| { |
| if (includesMatch == null) |
| includesMatch = new ArrayList(1); |
| includesMatch.add(s.substring(1, s.length() - 1)); |
| } |
| else |
| { |
| if (includesStart == null) |
| includesStart = new ArrayList(1); |
| includesStart.add(s); |
| } |
| } |
| } |
| List excludesStart = null; |
| List excludesMatch = null; |
| if (excludes != null) |
| { |
| for (Iterator it = excludes.iterator(); it.hasNext();) |
| { |
| String s = (String)it.next(); |
| if (s.charAt(0) == '*' && s.charAt(s.length() - 1) == '*') |
| { |
| if (excludesMatch == null) |
| excludesMatch = new ArrayList(1); |
| excludesMatch.add(s.substring(1, s.length() - 1)); |
| } |
| else |
| { |
| if (excludesStart == null) |
| excludesStart = new ArrayList(1); |
| excludesStart.add(s); |
| } |
| } |
| } |
| ComponentViolationEmitter compViolationEmitter = new ComponentViolationEmitter((String)compViolationDir.get(0)); |
| compViolationEmitter.setClassUseIncludes(includesStart); |
| compViolationEmitter.setClassUseExcludesMatch(includesMatch); |
| compViolationEmitter.setClassUseExcludes(excludesStart); |
| compViolationEmitter.setClassUseExcludesMatch(excludesMatch); |
| compViolationEmitter.setGenHTML(genHTML != null); |
| compViolationEmitter.setGenUsage(genUsage != null); |
| compViolationEmitter.setClassRefOnly(classRefOnly != null); |
| compViolationEmitter.setDebug(debug != null); |
| compViolationEmitter.init(eclipseDir, compXMLDir, compRefDir); |
| try |
| { |
| compViolationEmitter.genComponentViolationXML(); |
| } |
| catch (IOException ioe) |
| { |
| ioe.printStackTrace(); |
| } |
| } |
| |
| private static void printUsage() |
| { |
| System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.violaion.ComponentViolationEmitter -eclipseDir <eclipseDir> -compXMLDir <compXMLDir> -compVioDir <compVioDir> [-options]"); |
| System.out.println(""); |
| System.out.println("\t-eclipseDir\t<eclipseDir>\tspace seperated list of directories containing Eclipse plugins"); |
| System.out.println("\t-compXMLDir\t<compXMLDir>\tdirectories containing component.xml that will be checked for API violations"); |
| System.out.println("\t-compVioDir\t<compVioDir>\toutput directory of component-violation.xml"); |
| System.out.println(""); |
| System.out.println("where options include:"); |
| System.out.println(""); |
| System.out.println("\t-compRefDir\t<compRefDir>\tdirectories containing component.xml being referenced"); |
| System.out.println("\t-include\t<include>\tspace seperated packages to include"); |
| System.out.println("\t-exclude\t<exclude>\tspace seperated packages to exclude"); |
| System.out.println("\t-genHTML\t\t\tgenerate violation report in HTML"); |
| System.out.println("\t-genUsage\t\t\tgenerate component-use.xml"); |
| System.out.println("\t-classRefOnly\t\t\ttreat all violations as class reference"); |
| System.out.println("\t-debug\t\t\t\tgenerate debug information (ex. line numbers)"); |
| } |
| } |