blob: 0917092df126544c9a5455ebe82e1612663f34f5 [file] [log] [blame]
/**********************************************************************
* 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();
}
}