blob: 6e16fba2e96a1fb2cb304ccf38d4888c2cd6dccd [file] [log] [blame]
/**********************************************************************
* Copyright (c) 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.wtp.releng.tools.component.use;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.wtp.releng.tools.component.IClazz;
import org.eclipse.wtp.releng.tools.component.IClazzVisitor;
import org.eclipse.wtp.releng.tools.component.ILocation;
import org.eclipse.wtp.releng.tools.component.IPluginXML;
import org.eclipse.wtp.releng.tools.component.api.FieldAPI;
import org.eclipse.wtp.releng.tools.component.internal.AbstractEmitter;
import org.eclipse.wtp.releng.tools.component.internal.FieldRef;
import org.eclipse.wtp.releng.tools.component.internal.FileLocation;
import org.eclipse.wtp.releng.tools.component.internal.MethodRef;
import org.eclipse.wtp.releng.tools.component.model.ComponentXML;
import org.eclipse.wtp.releng.tools.component.model.Plugin;
import org.eclipse.wtp.releng.tools.component.use.ComponentUse;
import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser;
import org.eclipse.jdt.core.Signature;
public class ComponentUseEmitter extends AbstractEmitter implements IClazzVisitor
{
public static final String OPTION_ECLIPSE_DIR = "eclipseDir";
public static final String OPTION_COMPONENT_XML_DIR = "compXMLDir";
public static final String OPTION_COMPONENT_USE_DIR = "compUseDir";
public static final String OPTION_INCLUDE = "include";
public static final String OPTION_EXCLUDE = "exclude";
public static final String OPTION_CLASS_REF_ONLY = "classRefOnly";
public static final String OPTION_DEBUG = "debug";
private String compUseDir;
private Map pluginId2Plugin;
private Map fragmentId2Fragment;
private Map compLoc2CompXML;
private List classUseIncludes;
private List classUseExcludes;
private boolean classRefOnly;
private boolean debug;
private ComponentUse compUse;
public ComponentUseEmitter(String compUseDir)
{
this.compUseDir = addTrailingSeperator(compUseDir);
classRefOnly = false;
debug = false;
}
public void init(List eclipseDirs, List compXMLDirs)
{
compLoc2CompXML = 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);
}
}
public void init(Map compLoc2CompXML, Map pluginId2Plugin, Map fragmentId2Fragment)
{
this.compLoc2CompXML = compLoc2CompXML;
this.pluginId2Plugin = pluginId2Plugin;
this.fragmentId2Fragment = fragmentId2Fragment;
}
/**
* @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 List getClassUseIncludes()
{
return classUseIncludes;
}
public void setClassUseIncludes(List includes)
{
this.classUseIncludes = includes;
}
public List getClassUseExcludes()
{
return classUseExcludes;
}
public void setClassUseExcludes(List excludes)
{
this.classUseExcludes = excludes;
}
public void genComponentUseXML() throws IOException
{
for (Iterator it = compLoc2CompXML.keySet().iterator(); it.hasNext();)
genComponentUseXML((String)it.next());
}
public ComponentUse genComponentUseXML(String compLoc) throws IOException
{
ComponentXML compXML = (ComponentXML)compLoc2CompXML.get(compLoc);
if (compXML != null)
{
compXML.load();
String compName = compXML.getName();
compUse = newComponentUse(compXML);
for (Iterator pluginsIt = compXML.getPlugins().iterator(); pluginsIt.hasNext();)
{
IPluginXML pluginXML = (IPluginXML)pluginId2Plugin.get(((Plugin)pluginsIt.next()).getId());
if (pluginXML != null)
pluginXML.accept(this);
}
compXML = null;
if (compUseDir != null)
System.out.println("Writing component-use.xml for " + compName);
compUse.save();
return compUse;
}
return null;
}
public ComponentUse genAll() throws IOException
{
compUse = new ComponentUse();
for (Iterator it = pluginId2Plugin.values().iterator(); it.hasNext();)
((IPluginXML)it.next()).accept(this);
return compUse;
}
public Source genUse(IClazz clazz)
{
return newSource(clazz);
}
public boolean visit(IClazz clazz)
{
if (compUse == null)
return false;
Source source = newSource(clazz);
addSource(compUse, source);
return true;
}
private Source newSource(IClazz clazz)
{
String className = clazz.getName();
Source source = newSource(clazz.getName());
if (!classRefOnly)
{
// method references
List methodRefs = clazz.getMethodRefs(classUseIncludes, classUseExcludes, debug);
for (Iterator it = methodRefs.iterator(); it.hasNext();)
{
MethodRef methodRef = (MethodRef)it.next();
String refClassName = methodRef.getClassName();
String methodName = methodRef.getMethodName();
if (isConstructor(methodName))
{
// use: instantiate
addUniqueClassUse(source, refClassName, null, null, null, Boolean.TRUE, methodRef.getLines());
}
else
{
ClassUse classUse = addUniqueClassUse(source, refClassName, Boolean.TRUE, null, null, null, null);
MethodUse methodUse = newMethodUse(methodName, methodRef.getMethodDescriptor(), methodRef.getLines());
classUse.getMethodUses().add(methodUse);
}
}
clazz.resetMethodRefs();
methodRefs = null;
// field references
List fieldRefs = clazz.getFieldRefs(classUseIncludes, classUseExcludes, debug);
for (Iterator it = fieldRefs.iterator(); it.hasNext();)
{
FieldRef fieldRef = (FieldRef)it.next();
String refClassName = fieldRef.getClassName();
ClassUse classUse = addUniqueClassUse(source, refClassName, Boolean.TRUE, null, null, null, null);
FieldAPI fieldUse = newFieldUse(fieldRef.getFieldName(), fieldRef.getFieldDescriptor(), fieldRef.getLines());
classUse.getFieldAPIs().add(fieldUse);
}
clazz.resetFieldRefs();
fieldRefs = null;
// use: subclass
if (!clazz.isInterface())
{
String superClass = clazz.getSuperClass();
if (superClass != null && isReportClassUse(className, superClass))
addUniqueClassUse(source, superClass, null, Boolean.TRUE, null, null, null);
}
// use: implement
String[] interfaces = clazz.getInterfaces();
for (int i = 0; i < interfaces.length; i++)
addUniqueClassUse(source, interfaces[i], null, null, Boolean.TRUE, null, null);
}
// use: reference
Set refClasses = clazz.getReferencedTypes();
for (Iterator refClassesIt = refClasses.iterator(); refClassesIt.hasNext();)
{
String refClassName = (String)refClassesIt.next();
if (isReportClassUse(className, refClassName))
addUniqueClassUse(source, refClassName, Boolean.TRUE, null, null, null, null);
}
return source;
}
private boolean isReportClassUse(String sourceClassName, String classUseName)
{
if (sourceClassName != null && sourceClassName.equals(classUseName))
return false;
if (classUseExcludes != null)
for (Iterator it = classUseExcludes.iterator(); it.hasNext();)
if (classUseName.startsWith((String)it.next()))
return false;
if (classUseIncludes != null && classUseIncludes.size() > 0)
{
for (Iterator it = classUseIncludes.iterator(); it.hasNext();)
if (classUseName.startsWith((String)it.next()))
return true;
return false;
}
return true;
}
private boolean isConstructor(String methodName)
{
return methodName.equals("<init>");
}
private void addSource(ComponentUse compUse, Source source)
{
compUse.getSources().add(source);
}
private ClassUse addUniqueClassUse(Source source, String className, Boolean ref, Boolean subclass, Boolean implement, Boolean instantiate, List lines)
{
List classUses = source.getClassUses();
for (Iterator it = classUses.iterator(); it.hasNext();)
{
ClassUse classUse = (ClassUse)it.next();
if (!classUse.getName().equals(className))
continue;
if (ref != null && (classUse.getReference() == null || (ref.booleanValue() != classUse.isReference())))
continue;
if (subclass != null && (classUse.getSubclass() == null || (subclass.booleanValue() != classUse.isSubclass())))
continue;
if (implement != null && (classUse.getImplement() == null || (implement.booleanValue() != classUse.isImplement())))
continue;
if (instantiate != null && (classUse.getInstantiate() == null || (instantiate.booleanValue() != classUse.isInstantiate())))
continue;
if (lines != null)
classUse.getLines().addAll(lines);
return classUse;
}
ClassUse classUse = newClassUse(className, ref, subclass, implement, instantiate, lines);
classUses.add(classUse);
return classUse;
}
private ClassUse newClassUse(String className, Boolean ref, Boolean subclass, Boolean implement, Boolean instantiate, List lines)
{
ClassUse classUse = new ClassUse();
classUse.setName(className);
classUse.setReference(ref);
classUse.setSubclass(subclass);
classUse.setImplement(implement);
classUse.setInstantiate(instantiate);
if (lines != null)
classUse.getLines().addAll(lines);
return classUse;
}
private MethodUse newMethodUse(String methodName, String descriptor, List lines)
{
MethodUse methodUse = new MethodUse();
methodUse.setName(methodName);
methodUse.setDescriptor(descriptor);
if (lines != null)
methodUse.getLines().addAll(lines);
return methodUse;
}
private FieldUse newFieldUse(String fieldName, String descriptor, List lines)
{
FieldUse fieldUse = new FieldUse();
fieldUse.setName(fieldName);
fieldUse.setDescriptor(descriptor);
if (lines != null)
fieldUse.getLines().addAll(lines);
return fieldUse;
}
private ComponentUse newComponentUse(ComponentXML compXML)
{
String compName = compXML.getName();
ILocation location = null;
if (compUseDir != null)
{
StringBuffer sb = new StringBuffer(compUseDir);
sb.append(compName);
sb.append('/');
sb.append(ComponentUse.CONST_COMPONENT_USE_XML);
location = new FileLocation(new File(sb.toString()));
}
return newComponentUse(compName, location);
}
private ComponentUse newComponentUse(String name, ILocation location)
{
ComponentUse compUse = new ComponentUse();
compUse.setName(name);
compUse.setLocation(location);
return compUse;
}
private Source newSource(String className)
{
Source source = new Source();
source.setName(className);
return source;
}
private boolean isBit(int flag, int bit)
{
return ((flag & bit) == bit);
}
private String descriptor2Signature(char[] descriptor)
{
return toClassName(Signature.toString(new String(descriptor)));
}
private String toClassName(String className)
{
return className.replace('/', '.');
}
public static void main(String[] args)
{
CommandOptionParser optionParser = new CommandOptionParser(args);
Map options = optionParser.getOptions();
List eclipseDir = (List)options.get(ComponentUseEmitter.OPTION_ECLIPSE_DIR);
List compXMLDir = (List)options.get(ComponentUseEmitter.OPTION_COMPONENT_XML_DIR);
List compUseDir = (List)options.get(ComponentUseEmitter.OPTION_COMPONENT_USE_DIR);
List includes = (List)options.get(ComponentUseEmitter.OPTION_INCLUDE);
List excludes = (List)options.get(ComponentUseEmitter.OPTION_EXCLUDE);
List classRefOnly = (List)options.get(ComponentUseEmitter.OPTION_CLASS_REF_ONLY);
List debug = (List)options.get(ComponentUseEmitter.OPTION_DEBUG);
if (eclipseDir == null || compXMLDir == null || compUseDir == null || eclipseDir.size() < 1 || compXMLDir.size() < 1 || compUseDir.size() < 1)
{
printUsage();
System.exit(-1);
}
ComponentUseEmitter compUseEmitter = new ComponentUseEmitter((String)compUseDir.get(0));
compUseEmitter.setClassUseIncludes(includes);
compUseEmitter.setClassUseExcludes(excludes);
compUseEmitter.setClassRefOnly(classRefOnly != null);
compUseEmitter.setDebug(debug != null);
compUseEmitter.init(eclipseDir, compXMLDir);
try
{
compUseEmitter.genComponentUseXML();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
private static void printUsage()
{
System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.use.ComponentUseEmitter -eclipseDir <eclipseDir> -compXMLDir <compDir> [-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>\tdirectory containing component.xml");
System.out.println("\t-compUseDir\t<compUseDir>\toutput directory of component-use.xml");
System.out.println("");
System.out.println("where options include:");
System.out.println("");
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-classRefOnly\t\t\ttreat all violations as class reference");
System.out.println("\t-debug\t\t\t\tgenerate debug information (ex. line numbers)");
}
}