| /********************************************************************** |
| * Copyright (c) 2002, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| **********************************************************************/ |
| |
| package org.eclipse.component.internalreference; |
| |
| import java.io.File; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| import org.eclipse.component.location.ILocation; |
| import org.eclipse.component.location.Location; |
| import org.eclipse.component.util.CommandLineParser; |
| |
| /** |
| * Main entrance into the internal reference finder tool. To customize |
| * what types are considered internal, implement the IInternalRules |
| * and specify your class on the command line. For example: |
| * org.eclipse.api.internalreference.Main -internalRules com.myCo.MyRules |
| * <p> |
| * Supplied rule classes must have zero argument constructors. |
| */ |
| public class Main { |
| public static final String FILTER= "internalRules"; |
| |
| public static void main(String[] args) { |
| new Main().run(args); |
| } |
| |
| /** |
| * Performs sanity checks on the arguments and performs the internal |
| * reference check. |
| * @param args an array of arguments similar to main(String[] args) |
| */ |
| public void run(String[] args) { |
| CommandLineParser parser= new CommandLineParser(args); |
| Map options= parser.getOptions(); |
| List arguments= parser.getArguments(); |
| |
| if (arguments.size() != 2) { |
| System.out.println("Usage: org.eclipse.api.internalreference.Main [-internalRules <rules>] <report directory> <eclipse distribution>"); |
| System.out.println(); |
| System.out.println("<rules> is the name of the class used to specify custom internal rules"); |
| System.out.println("<report directory> will be the location of the generated report"); |
| System.out.println("<eclipse distribution> can be a folder or a zip file"); |
| System.exit(-1); |
| } |
| |
| String pathToProcess = (String)arguments.get(1); |
| String outputPath= (String)arguments.get(0); |
| File fileToProcess = new File(pathToProcess); |
| sanityCheck(fileToProcess); |
| |
| File outputDir= new File(outputPath); |
| sanityCheckDirectory(outputDir); |
| outputDir= createReportDirectory(outputDir, fileToProcess.getName()); |
| |
| System.out.println("Report directory " + outputDir); |
| |
| IInternalRules rules= new EclipseInternalRules(); |
| if (options.isEmpty() || options.get(FILTER) == null) { |
| System.out.println("Using the default filter, " + rules.getClass().toString()); |
| } else { |
| String filterClassName= (String)options.get(FILTER); |
| Object object= createInstance(filterClassName); |
| if (object != null) { |
| if (object instanceof IInternalRules) { |
| rules= (IInternalRules) object; |
| } else { |
| System.err.println("Specified filter, " + filterClassName + ", does not implement IInternalRules, using default filter."); |
| } |
| } |
| } |
| |
| ILocation inputLocation= Location.createLocation(fileToProcess); |
| if (inputLocation == null) { |
| System.out.println("input location invalid: " + inputLocation.getName()); |
| System.exit(-1); |
| } |
| |
| long time= System.currentTimeMillis(); |
| System.out.println("Locating plugins in " + fileToProcess); |
| ConfigurationFileLocator locator= new ConfigurationFileLocator(); |
| inputLocation.accept(locator); |
| Map pluginNamesToPlugins= locator.getPlugins(); |
| System.out.println("Plugins found: " + pluginNamesToPlugins.size() + " in " + (System.currentTimeMillis() - time) + "ms"); |
| linkFragments(pluginNamesToPlugins, locator.getFragments()); |
| System.out.println("Finding internal references"); |
| Map pluginNamesToInternalReferences= getInternalReferences(pluginNamesToPlugins, rules); |
| System.out.println("Plugins with internal references: " + pluginNamesToInternalReferences.size()); |
| ReportGenerator writer= new ReportGenerator(outputDir); |
| writer.writeInternalReferencesAsHTML(pluginNamesToInternalReferences, pluginNamesToPlugins); |
| System.out.println("Generating reports"); |
| time= System.currentTimeMillis() - time; |
| System.out.println("Done in " + time + "ms"); |
| } |
| |
| private void sanityCheck(File file) { |
| if (!file.exists()) { |
| System.err.println (file + " not found"); |
| System.exit(-1); |
| } |
| |
| if (!file.canRead()) { |
| System.err.println (file + " cannot be read"); |
| System.exit(-1); |
| } |
| } |
| |
| private void sanityCheckDirectory(File dir) { |
| if (!dir.exists()) { |
| if (!dir.mkdirs()) { |
| if (!dir.exists()) { |
| System.err.println (dir + " not found"); |
| System.exit(-1); |
| } |
| } |
| } |
| |
| if (!dir.canRead()) { |
| System.err.println (dir + " cannot be read"); |
| System.exit(-1); |
| } |
| |
| if (!dir.isDirectory()) { |
| System.err.println (dir + " is not a directory"); |
| System.exit(-1); |
| } |
| } |
| |
| /* |
| * Creates an instance of the class with the given name. |
| * |
| * @param className the name of the class to be instantiated |
| * @return Object the resulting object, or <code>null</code>. |
| */ |
| private Object createInstance(String className) { |
| Class clazz= null; |
| try { |
| clazz= Class.forName(className); |
| } catch (ClassNotFoundException e) { |
| System.err.println("Could not find " + className + ", using defualt filter."); |
| return null; |
| } |
| |
| try { |
| return clazz.newInstance(); |
| } catch (InstantiationException e) { |
| System.err.println("Could not find default constructor in " + className +", using default filter."); |
| return null; |
| } catch (IllegalAccessException e) { |
| System.err.println("Could not access " + className +", using default filter."); |
| return null; |
| } |
| } |
| |
| /* |
| * Links the fragments to the plugins. |
| * @param plugins a map of plugin names to plugin objects. |
| */ |
| private void linkFragments(Map plugins, Map fragments) { |
| for (Iterator i = fragments.values().iterator(); i.hasNext();) { |
| Fragment fragment= (Fragment) i.next(); |
| fragment.link(plugins); |
| } |
| } |
| |
| /* |
| * Answers a map of plugin identifiers to maps of internal references. |
| * |
| * @param pluginNameToPlugin a map of plugin names to plugin objects |
| * @param filter |
| * @return Map |
| */ |
| private Map getInternalReferences(Map pluginNameToPlugin, IInternalRules rules) { |
| Map pluginsToReferences= new TreeMap(); |
| for (Iterator i = pluginNameToPlugin.keySet().iterator(); i.hasNext();) { |
| String pluginName= (String)i.next(); |
| Plugin plugin = (Plugin) pluginNameToPlugin.get(pluginName); |
| long time= System.currentTimeMillis(); |
| Map internalReferences= getInternalReferences(plugin, rules, pluginNameToPlugin); |
| if (!internalReferences.isEmpty()) { |
| pluginsToReferences.put(plugin.getUniqueIdentifier(), internalReferences); |
| } |
| time= System.currentTimeMillis() - time; |
| System.out.println("analyzed: " + pluginName + " in " + time + "ms"); |
| } |
| return pluginsToReferences; |
| } |
| |
| /** |
| * Answers a mapping of (qualified) type name to a set of internal |
| * reference objects. |
| * |
| * @param plugin the plugin in which to find internal references |
| * @param rules a set of rules which dictates which references are internal |
| * @param pluginNameToPlugin a map of plugin names to plugin objects |
| * @return Map a map of type names to sets of internal reference objects |
| */ |
| private Map getInternalReferences(Plugin plugin, IInternalRules rules, Map pluginNameToPlugin) { |
| Map typeNameToInternalReferences= new TreeMap(); |
| List libraries= plugin.getLibraries(); |
| for (Iterator i = libraries.iterator(); i.hasNext();) { |
| Library library = (Library) i.next(); |
| Map types= library.getTypes(); |
| for (Iterator j = types.values().iterator(); j.hasNext();) { |
| Type type = (Type) j.next(); |
| Set referencedTypes= type.getReferencedTypes(); |
| if (!referencedTypes.isEmpty()) { |
| Set internalReferences= new TreeSet(new InternalReferenceComparator()); |
| for (Iterator k = referencedTypes.iterator(); k.hasNext();) { |
| String referencedType = (String) k.next(); |
| if (rules.isInternal(referencedType, type, library, plugin)) { |
| internalReferences.add(new InternalTypeReference(referencedType, getPluginFor(referencedType, pluginNameToPlugin))); |
| } |
| } |
| if (!internalReferences.isEmpty()) { |
| typeNameToInternalReferences.put(type.getName(), internalReferences); |
| } |
| } |
| } |
| } |
| return typeNameToInternalReferences; |
| } |
| |
| |
| /* |
| * Answers the name of the plugin that contains the given type. |
| * Assumes that only one plugin will contain the type name. This |
| * is a faulty assumption. |
| * |
| * @param typeName the name of the type being referenced |
| * @param pluginNameToPlugin a map of plugin name to plugin object |
| * @return String the name of the plugin which contains the referenced type |
| */ |
| public String getPluginFor(String typeName, Map pluginNameToPlugin) { |
| for (Iterator i = pluginNameToPlugin.values().iterator(); i.hasNext();) { |
| Plugin plugin = (Plugin) i.next(); |
| if (plugin.containsType(typeName)) { |
| return plugin.getName(); |
| } |
| } |
| return "unknown plugin"; |
| } |
| |
| /** |
| * Creates a directory in which the report will be created. |
| * @param parent the directory in which the directory will be created |
| * @param name the name of the report |
| * @return File the directory in which the report should be created |
| */ |
| private File createReportDirectory(File parent, String name) { |
| File reportDirectory; |
| int i= 0; |
| do { |
| String reportDirectoryName= getReportDirectoryName(i, name); |
| reportDirectory= new File(parent, reportDirectoryName); |
| i++; |
| } while (reportDirectory.exists()); |
| reportDirectory.mkdirs(); |
| return reportDirectory; |
| } |
| |
| /** |
| * Answers the name of the directory to be created for storing the |
| * reports. |
| * |
| * @param attempt an integer to be tacked on the end of the directory name |
| * @param name a name for the report directory |
| * @return String the report directory name |
| */ |
| private String getReportDirectoryName(int attempt, String name) { |
| StringBuffer b= new StringBuffer(); |
| b.append("internal_"); |
| b.append(name); |
| b.append('_'); |
| b.append(attempt); |
| return b.toString(); |
| } |
| } |