blob: a3cb3604b006623227a82e0ba87b295cd57aa744 [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 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.adopters;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import org.eclipse.core.runtime.IPlatformRunnable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.core.util.IClassFileReader;
import org.eclipse.jdt.core.util.ICodeAttribute;
import org.eclipse.jdt.core.util.IConstantPool;
import org.eclipse.jdt.core.util.IConstantPoolConstant;
import org.eclipse.jdt.core.util.IConstantPoolEntry;
import org.eclipse.jdt.core.util.IFieldInfo;
import org.eclipse.jdt.core.util.ILineNumberAttribute;
import org.eclipse.jdt.core.util.IMethodInfo;
import org.eclipse.jdt.internal.core.util.ClassFileReader;
import org.eclipse.wtp.releng.tools.component.CommandOptionParser;
import org.eclipse.wtp.releng.tools.component.IClassVisitor;
import org.eclipse.wtp.releng.tools.component.ILocation;
import org.eclipse.wtp.releng.tools.component.api.API2ComponentAPI;
import org.eclipse.wtp.releng.tools.component.api.ComponentAPI;
import org.eclipse.wtp.releng.tools.component.api.ComponentAPICache;
import org.eclipse.wtp.releng.tools.component.api.violation.LibVisitor;
import org.eclipse.wtp.releng.tools.component.internal.FieldRef;
import org.eclipse.wtp.releng.tools.component.internal.InternalByteCodeVisitor;
import org.eclipse.wtp.releng.tools.component.internal.Location;
import org.eclipse.wtp.releng.tools.component.internal.MethodRef;
import org.eclipse.wtp.releng.tools.component.xsl.XSLUtil;
public class SimpleClass2Reference implements IPlatformRunnable, IClassVisitor
{
private Collection src;
private String base;
private String output;
private String contactInfo;
private ComponentAPICache compAPICache;
private String html;
private Collection includes;
private Collection excludes;
private Collection includePlugins;
private Collection excludePlugins;
public void setCompAPIDir(String compAPIDir)
{
compAPICache = new ComponentAPICache(compAPIDir);
}
public String getContactInfo()
{
return contactInfo;
}
public void setContactInfo(String contactInfo)
{
this.contactInfo = contactInfo;
}
public String getBase()
{
return base;
}
public void setBase(String base)
{
this.base = base;
}
public String getOutput()
{
return output;
}
public void setOutput(String output)
{
this.output = addTrailingSeperator(output);
}
public String getHTML()
{
return html;
}
public void setHTML(String html)
{
this.html = html;
}
public Collection getSrc()
{
return src;
}
public void setSrc(Collection src)
{
this.src = new ArrayList(src);
}
public Collection getIncludes()
{
return includes;
}
public void setIncludes(Collection includes)
{
this.includes = includes;
}
public Collection getExcludes()
{
return excludes;
}
public void setExcludes(Collection excludes)
{
this.excludes = excludes;
}
public Collection getExcludePlugins()
{
return excludePlugins;
}
public void setExcludePlugins(Collection excludePlugins)
{
this.excludePlugins = excludePlugins;
}
public Collection getIncludePlugins()
{
return includePlugins;
}
public void setIncludePlugins(Collection includePlugins)
{
this.includePlugins = includePlugins;
}
private References refs;
public void execute()
{
refs = new References();
refs.setName(src.toString());
refs.setRefBuildId(base);
refs.setContactInfo(contactInfo);
if (includes != null)
refs.setIncludes(includes.toString());
if (excludes != null)
refs.setExcludes(excludes.toString());
if (includePlugins != null)
refs.setIncludePlugins(includePlugins.toString());
if (excludePlugins != null)
refs.setExcludePlugins(excludePlugins.toString());
for (Iterator it = src.iterator(); it.hasNext();)
{
ILocation srcLocation = Location.createLocation(new File((String)it.next()));
LibVisitor libVisitor = new LibVisitor();
srcLocation.accept(libVisitor);
libVisitor.setClassVisitor(this);
srcLocation.accept(libVisitor);
}
try
{
save();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public void save() throws IOException
{
File file = new File(output);
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
refs.write(fos);
fos.close();
if (html != null)
genHTML(file);
}
private void genHTML(File f)
{
try
{
int i = html.replace('\\', '/').lastIndexOf("/");
String htmlDir = i != -1 ? html.substring(0, i + 1) : html;
XSLUtil.transform(Platform.getBundle("org.eclipse.wtp.releng.tools.component.core").getResource("org/eclipse/wtp/releng/tools/component/xsl/api-ref-compatibility.xsl").openStream(), f, new FileOutputStream(html), htmlDir);
}
catch (Throwable e)
{
throw new RuntimeException(e);
}
}
public boolean visit(String pluginId, ILocation classLoc)
{
if (includePlugins(pluginId))
{
try
{
visit(classLoc);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
catch (ClassFormatException e)
{
System.err.println("Plugin: " + pluginId + " Class: " + classLoc.getAbsolutePath());
//throw new RuntimeException(e);
}
}
return true;
}
public References visit(ILocation classLoc) throws IOException, ClassFormatException
{
IClassFileReader reader = read(classLoc);
String className = new String(reader.getClassName()).replace('/', '.');
// use: reference
for (Iterator it = getReferencedTypes(reader).iterator(); it.hasNext();)
{
String refClassName = (String)it.next();
if (!className.equals(refClassName) && include(refClassName))
{
getClassRef(refClassName).incRefCount();
}
}
// method info & field info
setMethodAndFieldInfoUses(reader);
// method ref
List methodRefs = new ArrayList();
List fieldRefs = new ArrayList();
getRefs(reader, false, methodRefs, fieldRefs);
for (Iterator it = methodRefs.iterator(); it.hasNext();)
{
MethodRef methodRef = (MethodRef)it.next();
String refClassName = methodRef.getClassName();
if (!className.equals(refClassName) && include(refClassName))
{
String methodName = methodRef.getMethodName();
String methodDesc = methodRef.getMethodDescriptor();
ClassRef classRef = getClassRef(refClassName);
if (methodRef.isConstructor())
{
// use: instantiate
classRef.incInstantiateCount();
}
else
{
// use: reference
classRef.incRefCount();
}
getMethodRef(classRef, methodName, methodDesc).incRefCount();
}
}
methodRefs = null;
// field ref
for (Iterator it = fieldRefs.iterator(); it.hasNext();)
{
FieldRef fieldRef = (FieldRef)it.next();
String refClassName = fieldRef.getClassName();
if (!className.equals(refClassName) && include(refClassName))
{
getFieldRef(getClassRef(refClassName), fieldRef.getFieldName(), fieldRef.getFieldDescriptor()).incRefCount();
}
}
fieldRefs = null;
// use: subclass
String superClass = new String(reader.getSuperclassName()).replace('/', '.');
if (superClass != null && include(superClass))
{
getClassRef(superClass).incSubclassCount();
}
// use: implement
char[][] interfaceNames = reader.getInterfaceNames();
String[] interfaces = new String[interfaceNames.length];
for (int i = 0; i < interfaces.length; i++)
interfaces[i] = new String(interfaceNames[i]).replace('/', '.');
for (int i = 0; i < interfaces.length; i++)
if (include(interfaces[i]))
getClassRef(interfaces[i]).incImplementCount();
return refs;
}
private IClassFileReader read(ILocation classLoc) throws IOException, ClassFormatException
{
InputStream is = null;
ByteArrayOutputStream baos = null;
try
{
byte[] b = new byte[8192];
baos = new ByteArrayOutputStream(8192);
is = classLoc.getInputStream();
for (int read = is.read(b); read != -1; read = is.read(b))
{
baos.write(b, 0, read);
}
is.close();
baos.close();
return new ClassFileReader(baos.toByteArray(), IClassFileReader.CONSTANT_POOL | IClassFileReader.METHOD_INFOS | IClassFileReader.METHOD_BODIES | IClassFileReader.FIELD_INFOS | IClassFileReader.SUPER_INTERFACES);
}
finally
{
if (is != null)
{
try
{
is.close();
}
catch (IOException e)
{
}
}
if (baos != null)
{
try
{
baos.close();
}
catch (IOException e)
{
}
}
}
}
private Set getReferencedTypes(IClassFileReader reader)
{
Set types = new HashSet();
IConstantPool constantPool = reader.getConstantPool();
int poolSize = constantPool.getConstantPoolCount();
for (int i = 0; i < poolSize; i++)
{
// Extract the constant's referenced class (if that is even relevant)
if (constantPool.getEntryKind(i) == IConstantPoolConstant.CONSTANT_Class)
{
IConstantPoolEntry classEntry = constantPool.decodeEntry(i);
String signature = new String(classEntry.getClassInfoName());
int index = signature.lastIndexOf('[');
if (index > -1)
{
// could be an array of a primitive type
if (signature.length() - (index + 1) == 1)
continue;
signature = Signature.toString(signature);
signature = signature.substring(0, signature.length() - 2 * (index + 1));
signature = signature.replace('.', '$');
}
String typeName = signature.replace('/', '.');
types.add(typeName);
}
}
return types;
}
private void getRefs(IClassFileReader reader, boolean debug, List methodRefs, List fieldRefs)
{
String className = new String(reader.getClassName()).replace('/', '.');
IConstantPoolEntry[] refs = getConstantPoolEntries(reader, IConstantPoolConstant.CONSTANT_Methodref);
for (int i = 0; i < refs.length; i++)
{
String refClassName = new String(refs[i].getClassName()).replace('/', '.');
if (!className.equals(refClassName) && include(refClassName))
{
MethodRef methodRef = new MethodRef();
methodRef.setPoolEntry(refs[i]);
methodRefs.add(methodRef);
}
}
refs = getConstantPoolEntries(reader, IConstantPoolConstant.CONSTANT_InterfaceMethodref);
for (int i = 0; i < refs.length; i++)
{
String refClassName = new String(refs[i].getClassName()).replace('/', '.');
if (!className.equals(refClassName) && include(refClassName))
{
MethodRef methodRef = new MethodRef();
methodRef.setPoolEntry(refs[i]);
methodRefs.add(methodRef);
}
}
refs = getConstantPoolEntries(reader, IConstantPoolConstant.CONSTANT_Fieldref);
for (int i = 0; i < refs.length; i++)
{
String refClassName = new String(refs[i].getClassName()).replace('/', '.');
if (!className.equals(refClassName) && include(refClassName))
{
FieldRef fieldRef = new FieldRef();
fieldRef.setPoolEntry(refs[i]);
fieldRefs.add(fieldRef);
}
}
if (debug)
{
IMethodInfo[] methodInfos = reader.getMethodInfos();
for (int i = 0; i < methodInfos.length; i++)
{
ICodeAttribute codeAttr = methodInfos[i].getCodeAttribute();
if (codeAttr != null)
{
ILineNumberAttribute lineNumAttr = codeAttr.getLineNumberAttribute();
if (lineNumAttr != null)
{
InternalByteCodeVisitor byteCodeVisitor = new InternalByteCodeVisitor(methodRefs, fieldRefs, lineNumAttr);
try
{
codeAttr.traverse(byteCodeVisitor);
}
catch (ClassFormatException e)
{
e.printStackTrace();
}
}
}
}
}
}
private void setMethodAndFieldInfoUses(IClassFileReader reader)
{
String className = new String(reader.getClassName()).replace('/', '.');
IMethodInfo[] methodInfos = reader.getMethodInfos();
for (int i = 0; i < methodInfos.length; i++)
{
String desc = new String(methodInfos[i].getDescriptor());
String returnTypeDesc = Signature.getReturnType(desc);
String returnType = toFullyQualifiedName(returnTypeDesc);
if (Signature.getTypeSignatureKind(returnTypeDesc) != Signature.BASE_TYPE_SIGNATURE && !className.equals(returnType) && include(returnType))
{
getClassRef(returnType).incRefCount();
}
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 && !className.equals(param) && include(param))
{
getClassRef(param).incRefCount();
}
}
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 && !className.equals(throwType) && include(throwType))
{
getClassRef(throwType).incRefCount();
}
}
}
IFieldInfo[] fieldInfos = reader.getFieldInfos();
for (int i = 0; i < fieldInfos.length; i++)
{
String desc = new String(fieldInfos[i].getDescriptor());
String field = toFullyQualifiedName(desc);
if (Signature.getTypeSignatureKind(desc) != Signature.BASE_TYPE_SIGNATURE && !className.equals(field) && include(field))
{
getClassRef(field).incRefCount();
}
}
}
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 IConstantPoolEntry[] getConstantPoolEntries(IClassFileReader reader, int kind)
{
List entries = new Vector();
IConstantPool pool = reader.getConstantPool();
int poolSize = pool.getConstantPoolCount();
for (int i = 0; i < poolSize; i++)
if (pool.getEntryKind(i) == kind)
entries.add(pool.decodeEntry(i));
return (IConstantPoolEntry[])entries.toArray(new IConstantPoolEntry[0]);
}
private ClassRef getClassRef(String name)
{
ComponentAPI compAPI = compAPICache.getComponentAPIByClassName(name);
String pluginId = compAPI != null ? compAPI.getName() : "unknown";
PluginRef pluginRef = refs.getPluginRef(pluginId);
if (pluginRef == null)
{
pluginRef = new PluginRef();
pluginRef.setId(pluginId);
refs.addPluginRef(pluginRef);
}
ClassRef classRef = pluginRef.getClassRef(name);
if (classRef == null)
{
classRef = new ClassRef();
classRef.setName(name);
pluginRef.addClassRef(classRef);
}
return classRef;
}
private org.eclipse.wtp.releng.tools.component.adopters.MethodRef getMethodRef(ClassRef classRef, String name, String descriptor)
{
org.eclipse.wtp.releng.tools.component.adopters.MethodRef methodRef = classRef.getMethodRef(name, descriptor);
if (methodRef == null)
{
methodRef = new org.eclipse.wtp.releng.tools.component.adopters.MethodRef();
methodRef.setName(name);
methodRef.setDescriptor(descriptor);
classRef.addMethodRef(methodRef);
}
return methodRef;
}
private org.eclipse.wtp.releng.tools.component.adopters.FieldRef getFieldRef(ClassRef classRef, String name, String descriptor)
{
org.eclipse.wtp.releng.tools.component.adopters.FieldRef fieldRef = classRef.getFieldRef(name, descriptor);
if (fieldRef == null)
{
fieldRef = new org.eclipse.wtp.releng.tools.component.adopters.FieldRef();
fieldRef.setName(name);
fieldRef.setDescriptor(descriptor);
classRef.addFieldRef(fieldRef);
}
return fieldRef;
}
private boolean include(String name)
{
name = name.replace('/', '.');
name = name.replace('\\', '.');
if (excludes != null && !excludes.isEmpty())
for (Iterator it = excludes.iterator(); it.hasNext();)
if (name.matches((String)it.next()))
return false;
if (includes != null && !includes.isEmpty())
{
for (Iterator it = includes.iterator(); it.hasNext();)
if (name.matches((String)it.next()))
return true;
return false;
}
return true;
}
private boolean includePlugins(String id)
{
id = id.replace('/', '.');
id = id.replace('\\', '.');
if (excludePlugins != null && !excludePlugins.isEmpty())
for (Iterator it = excludePlugins.iterator(); it.hasNext();)
if (id.matches((String)it.next()))
return false;
if (includePlugins != null && !includePlugins.isEmpty())
{
for (Iterator it = includePlugins.iterator(); it.hasNext();)
if (id.matches((String)it.next()))
return true;
return false;
}
return true;
}
protected static String addTrailingSeperator(String s)
{
if (s != null && !s.endsWith("/") && !s.endsWith("\\"))
{
StringBuffer sb = new StringBuffer(s);
sb.append('/');
return sb.toString();
}
else
{
return s;
}
}
public Object run(Object arguments)
{
String src = System.getProperty("src");
String base = System.getProperty("base");
String output = System.getProperty("output");
String contactInfo = System.getProperty("contactInfo");
String html = System.getProperty("html");
String includes = System.getProperty("includes");
String excludes = System.getProperty("excludes");
String includePlugins = System.getProperty("includePlugins");
String excludePlugins = System.getProperty("excludePlugins");
List args = new ArrayList();
args.add("-src");
args.addAll(tokenize(src));
args.add("-base");
args.add(base);
args.add("-output");
args.add(output);
args.add("-contactInfo");
args.add(contactInfo);
args.add("-html");
args.add(html);
if (includes != null)
{
args.add("-includes");
args.addAll(tokenize(includes));
}
if (excludes != null)
{
args.add("-excludes");
args.addAll(tokenize(excludes));
}
if (includePlugins != null)
{
args.add("-includePlugins");
args.addAll(tokenize(includePlugins));
}
if (excludePlugins != null)
{
args.add("-excludePlugins");
args.addAll(tokenize(excludePlugins));
}
try
{
main((String[])args.toArray(new String[0]));
}
catch (Throwable t)
{
t.printStackTrace();
}
return IPlatformRunnable.EXIT_OK;
}
private List tokenize(String s)
{
StringTokenizer st = new StringTokenizer(s, ",");
List tokens = new ArrayList(st.countTokens());
while(st.hasMoreTokens())
tokens.add(st.nextToken());
return tokens;
}
public static void main(String[] args)
{
CommandOptionParser optionParser = new CommandOptionParser(args);
Map options = optionParser.getOptions();
Collection src = (Collection)options.get("src");
Collection base = (Collection)options.get("base");
Collection output = (Collection)options.get("output");
Collection contactInfo = (Collection)options.get("contactInfo");
Collection html = (Collection)options.get("html");
Collection includes = (Collection)options.get("includes");
Collection excludes = (Collection)options.get("excludes");
Collection includePlugins = (Collection)options.get("includePlugins");
Collection excludePlugins = (Collection)options.get("excludePlugins");
if (src == null || base == null || output == null || contactInfo == null || src.isEmpty() || base.isEmpty() || output.isEmpty() || contactInfo.isEmpty())
{
printUsage();
System.exit(-1);
}
String outputString = (String)output.iterator().next();
int i = outputString.replace('\\', '/').lastIndexOf('/');
String outputDir = outputString.substring(0, i + 1);
String componentxml = outputDir + "_tmp_componentxml";
String componentapi = outputDir + "_tmp_componentapi";
Plugin2API plugin2API = new Plugin2API();
plugin2API.setSrc(base);
plugin2API.setOutputDir(componentxml);
plugin2API.execute();
API2ComponentAPI api2CompAPI = new API2ComponentAPI();
api2CompAPI.setApi(componentxml);
api2CompAPI.setSrc(base);
api2CompAPI.setOutputDir(componentapi);
api2CompAPI.setIncludeInnerClass(true);
api2CompAPI.setIncludeInterfaces(true);
api2CompAPI.execute();
SimpleClass2Reference class2Ref = new SimpleClass2Reference();
class2Ref.setSrc(src);
class2Ref.setBase((String)base.iterator().next());
class2Ref.setOutput(outputString);
class2Ref.setContactInfo((String)contactInfo.iterator().next());
class2Ref.setCompAPIDir(componentapi);
if (!html.isEmpty())
class2Ref.setHTML((String)html.iterator().next());
class2Ref.setIncludes(includes);
class2Ref.setExcludes(excludes);
class2Ref.setIncludePlugins(includePlugins);
class2Ref.setExcludePlugins(excludePlugins);
class2Ref.execute();
}
private static void printUsage()
{
System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.adopters.SimpleClass2Reference -src <src> -output <output> [-options]");
System.out.println("");
System.out.println("\t-src\t\t<src>\t\tlocation of your Eclipse-based product");
System.out.println("\t-base\t\t<base>\t\tlocation of your base build");
System.out.println("\t-output\t\t<output>\toutput file");
System.out.println("\t-contactInfo\t<contactInfo>\tadopter contact information");
System.out.println("");
System.out.println("where options include:");
System.out.println("");
System.out.println("\t-includes\t<includes>\tspace seperated packages to include");
System.out.println("\t-excludes\t<excludes>\tspace seperated packages to exclude");
System.out.println("\t-includePlugins\t<includePlugins>\tspace seperated plugins to include");
System.out.println("\t-excludePlugins\t<excludePlugins>\tspace seperated plugins to exclude");
System.out.println("\t-html\t\t\t\t<html>\toutput HTML file");
}
}