blob: bc3b957153f4dc5b110613de8e54339f3fce8cdb [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.api.violation;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.util.IModifierConstants;
import org.eclipse.wtp.releng.tools.component.api.ClassAPI;
import org.eclipse.wtp.releng.tools.component.api.ComponentAPI;
import org.eclipse.wtp.releng.tools.component.api.ComponentAPIEmitter;
import org.eclipse.wtp.releng.tools.component.api.FieldAPI;
import org.eclipse.wtp.releng.tools.component.api.MethodAPI;
import org.eclipse.wtp.releng.tools.component.api.PackageAPI;
import org.eclipse.wtp.releng.tools.component.internal.AbstractEmitter;
import org.eclipse.wtp.releng.tools.component.internal.ComponentEntry;
import org.eclipse.wtp.releng.tools.component.internal.ComponentSummary;
import org.eclipse.wtp.releng.tools.component.internal.FileLocation;
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.Type;
import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser;
import org.xml.sax.SAXException;
public class ComponentAPIViolationEmitter extends AbstractEmitter
{
private List compXMLDirs;
private List compXMLRefDirs;
private List eclipseDirs;
private List includes;
private List excludes;
private String outputDir;
private Map compLoc2CompXML;
private Map compLoc2CompRef;
private Map pluginId2Plugin;
private Map fragmentId2Fragment;
public ComponentAPIViolationEmitter(List compXMLDirs, List compXMLRefDirs, List eclipseDirs, List includes, List excludes, String outputDir)
{
this.compXMLDirs = compXMLDirs;
this.compXMLRefDirs = compXMLRefDirs;
this.eclipseDirs = eclipseDirs;
this.includes = includes;
this.excludes = excludes;
this.outputDir = addTrailingSeperator(outputDir);
}
public void genAPIViolations() throws ParserConfigurationException, SAXException, IOException, TransformerConfigurationException, TransformerException
{
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);
}
compLoc2CompRef.putAll(compLoc2CompXML);
if (compXMLRefDirs != null)
{
for (Iterator it = compXMLRefDirs.iterator(); it.hasNext();)
{
File compXMLRefFile = new File(addTrailingSeperator((String)it.next()));
if (compXMLRefFile.exists())
harvestComponents(compXMLRefFile, compLoc2CompRef);
}
}
ComponentSummary summary = new ComponentSummary();
for (Iterator it = compLoc2CompXML.keySet().iterator(); it.hasNext();)
{
String compLoc = (String)it.next();
ComponentAPIEmitter compAPIEmitter = new ComponentAPIEmitter(null);
compAPIEmitter.init(compLoc2CompXML, pluginId2Plugin, fragmentId2Fragment);
ComponentAPI compAPI = compAPIEmitter.genComponentApiXml(compLoc);
ComponentAPIViolation v = genAPIViolation(compAPI);
String compName = compAPI.getName();
StringBuffer sb = new StringBuffer(outputDir);
sb.append(compName);
sb.append("/component-api-violation.xml");
File file = new File(sb.toString());
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
fos.write(v.toString().getBytes());
fos.close();
ComponentEntry entry = new ComponentEntry();
entry.setCompName(compName);
sb = new StringBuffer("./");
sb.append(compName);
sb.append("/component-api-violation.xml");
entry.setRef(sb.toString());
summary.add(entry);
}
summary.save(new FileLocation(new File(outputDir + "component-api-violation-all.xml")));
xslt(summary.toString(), "org/eclipse/wtp/releng/tools/component/xsl/component-api-violation.xsl", outputDir + "component-api-violation-all.html");
}
private void xslt(String content, String xsl, String output) throws SAXException, ParserConfigurationException, TransformerConfigurationException, TransformerException, FileNotFoundException
{
File outputFile = new File(output);
outputFile.getParentFile().mkdirs();
xslt(new ByteArrayInputStream(content.getBytes()), xsl, new FileOutputStream(outputFile));
}
private void xslt(InputStream is, String xsl, OutputStream os) throws SAXException, ParserConfigurationException, TransformerConfigurationException, TransformerException, FileNotFoundException
{
String user_dir = "user.dir";
String currUserDir = System.getProperty(user_dir);
System.setProperty(user_dir, outputDir);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(ClassLoader.getSystemResourceAsStream(xsl)));
transformer.transform(new StreamSource(is), new StreamResult(os));
System.setProperty(user_dir, currUserDir);
}
private ComponentAPIViolation genAPIViolation(ComponentAPI compAPI)
{
ComponentAPIViolation v = new ComponentAPIViolation();
v.setName(compAPI.getName());
for (Iterator it = compAPI.getPackageAPIs().iterator(); it.hasNext();)
v.addAllViolations(genAPIViolation((PackageAPI)it.next()));
return v;
}
private List genAPIViolation(PackageAPI pkgAPI)
{
List classViolations = new ArrayList();
for (Iterator it = pkgAPI.getClassAPIs().iterator(); it.hasNext();)
{
ClassViolation classViolation = genAPIViolation((ClassAPI)it.next());
if (classViolation != null)
classViolations.add(classViolation);
}
return classViolations;
}
private ClassViolation genAPIViolation(ClassAPI classAPI)
{
ClassViolation classViolation = new ClassViolation();
classViolation.setName(classAPI.getName());
boolean isSuperClassAPI;
String superClassName = classAPI.getSuperClass();
if (checkAccess(classAPI.getAccess(), IModifierConstants.ACC_INTERFACE))
isSuperClassAPI = isAPI(superClassName, false, false, true, false);
else
isSuperClassAPI = isAPI(superClassName, false, true, false, false);
if (!isSuperClassAPI)
{
SuperViolation superViolation = new SuperViolation();
superViolation.setName(superClassName);
classViolation.addViolation(superViolation);
}
for (Iterator it = classAPI.getMethodAPIs().iterator(); it.hasNext();)
{
MethodAPI methodAPI = (MethodAPI)it.next();
MethodViolation methodViolation = new MethodViolation();
methodViolation.setName(methodAPI.getName());
String desc = methodAPI.getDescriptor();
String returnTypeDesc = Signature.getReturnType(desc);
String returnType = toFullyQualifiedName(returnTypeDesc);
if (Signature.getTypeSignatureKind(returnTypeDesc) != Signature.BASE_TYPE_SIGNATURE && !isAPI(returnType, true, false, false, false))
{
ReturnViolation returnViolation = new ReturnViolation();
returnViolation.setName(returnType);
methodViolation.addViolation(returnViolation);
}
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 && !isAPI(param, true, false, false, false))
{
ParamViolation paramViolation = new ParamViolation();
paramViolation.setName(param);
methodViolation.addViolation(paramViolation);
}
}
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 && !isAPI(throwType, true, false, false, false))
{
ThrowViolation throwViolation = new ThrowViolation();
throwViolation.setName(throwType);
methodViolation.addViolation(throwViolation);
}
}
if (methodViolation.countViolations() > 0)
classViolation.addViolation(methodViolation);
}
for (Iterator it = classAPI.getFieldAPIs().iterator(); it.hasNext();)
{
FieldAPI fieldAPI = (FieldAPI)it.next();
String desc = new String(fieldAPI.getDescriptor());
String field = toFullyQualifiedName(desc);
if (Signature.getTypeSignatureKind(desc) != Signature.BASE_TYPE_SIGNATURE && !isAPI(field, true, false, false, false))
{
FieldViolation fieldViolation = new FieldViolation();
fieldViolation.setName(fieldAPI.getName());
fieldViolation.setType(field);
classViolation.addViolation(fieldViolation);
}
}
if (classViolation.countViolations() > 0)
return classViolation;
else
return null;
}
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 boolean checkAccess(int flag, int bit)
{
return ((flag & bit) == bit);
}
private boolean isAPI(String className, boolean ref, boolean subclass, boolean implement, boolean instantiate)
{
if (include(className))
{
String pkgName = null;
String typeName = null;
int dot = className.lastIndexOf('.');
if (dot != -1)
{
pkgName = className.substring(0, dot);
typeName = className.substring(dot + 1);
}
if (pkgName != null && typeName != null)
{
for (Iterator it = compLoc2CompRef.values().iterator(); it.hasNext();)
{
ComponentXML compXML = (ComponentXML)it.next();
for (Iterator pkgIt = compXML.getPackages().iterator(); pkgIt.hasNext();)
{
Package pkg = (Package)pkgIt.next();
if (pkgName.equals(pkg.getName()))
{
// if not overwritten, inner class inherits usages from base class
int index = typeName.indexOf('$');
String baseTypeName = (index != -1) ? typeName.substring(0, index) : null;
Type baseType = null;
for (Iterator typeIt = pkg.getTypes().iterator(); typeIt.hasNext();)
{
Type type = (Type)typeIt.next();
String name = type.getName();
if (typeName.equals(name))
{
if (ref && !type.isReference())
return false;
if (subclass && !type.isSubclass())
return false;
if (implement && !type.isImplement())
return false;
if (instantiate && !type.isInstantiate())
return false;
return true;
}
if (baseTypeName != null && baseType == null && baseTypeName.equals(name))
{
baseType = type;
}
}
if (baseType != null)
{
if (ref && !baseType.isReference())
return false;
if (subclass && !baseType.isSubclass())
return false;
if (implement && !baseType.isImplement())
return false;
if (instantiate && !baseType.isInstantiate())
return false;
return true;
}
return pkg.isApi();
}
}
}
}
return false;
}
else
{
return true;
}
}
private boolean include(String className)
{
if (excludes != null)
for (Iterator it = excludes.iterator(); it.hasNext();)
if (className.startsWith((String)it.next()))
return false;
if (includes != null && includes.size() > 0)
{
for (Iterator it = includes.iterator(); it.hasNext();)
if (className.startsWith((String)it.next()))
return true;
return false;
}
return true;
}
public static void main(String[] args)
{
CommandOptionParser optionParser = new CommandOptionParser(args);
Map options = optionParser.getOptions();
List compXMLDirs = (List)options.get("compXMLDirs");
List compXMLRefDirs = (List)options.get("compXMLRefDirs");
List eclipseDirs = (List)options.get("eclipseDirs");
List outputDir = (List)options.get("outputDir");
List includes = (List)options.get("includes");
List excludes = (List)options.get("excludes");
if (compXMLDirs == null || eclipseDirs == null || outputDir == null || compXMLDirs.size() < 1 || eclipseDirs.size() < 1 || outputDir.size() < 1)
{
printUsage();
System.exit(-1);
}
ComponentAPIViolationEmitter emitter = new ComponentAPIViolationEmitter(compXMLDirs, compXMLRefDirs, eclipseDirs, includes, excludes, (String)outputDir.get(0));
try
{
emitter.genAPIViolations();
}
catch (Throwable t)
{
t.printStackTrace();
}
}
private static void printUsage()
{
System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.api.violation.APIViolationEmitter -compXMLDirs <compXMLDirs> -eclipseDirs <eclipseDirs> -outputDir <outputDir> [-options]");
System.out.println("");
System.out.println("\t-compXMLDirs\t<compXMLDirs>\tspace seperated list of directories containing component.xml files");
System.out.println("\t-eclipseDirs\t<eclipseDirs>\tspace seperated list of directories containing Eclipse plugins");
System.out.println("\t-outputDir\t<outputDir>\toutput directory");
System.out.println("");
System.out.println("where options include:");
System.out.println("");
System.out.println("\t-compXMLRefDirs\t<compXMLRefDirs>\tspace seperated list of directories containing component.xml files being referenced");
System.out.println("\t-includes\t<includes>\tpackages to include");
System.out.println("\t-excludes\t<excludes>\tpackages to exclude");
}
}