blob: 41faec5582a3c4a5bcd99161bbc4c5e5275099a0 [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;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
import org.eclipse.wtp.releng.tools.component.api.ApiFactory;
import org.eclipse.wtp.releng.tools.component.api.ApiTypes;
import org.eclipse.wtp.releng.tools.component.api.ClassApi;
import org.eclipse.wtp.releng.tools.component.api.ComponentApiType;
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.Package;
import org.eclipse.wtp.releng.tools.component.model.ComponentDependsType;
import org.eclipse.wtp.releng.tools.component.model.ComponentRefType;
import org.eclipse.wtp.releng.tools.component.model.ComponentType;
import org.eclipse.wtp.releng.tools.component.use.ComponentUseType;
import org.eclipse.wtp.releng.tools.component.use.SourceClass;
import org.eclipse.wtp.releng.tools.component.use.UseFactory;
import org.eclipse.wtp.releng.tools.component.use.UsePackage;
import org.eclipse.wtp.releng.tools.component.use.util.UseResourceFactoryImpl;
import org.eclipse.wtp.releng.tools.component.use.util.UseResourceImpl;
import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser;
import org.eclipse.wtp.releng.tools.component.util.EmitterUtils;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
public class APIViolationEmitter
{
public static final String OPTION_COMPONENT_DIR = "compDir";
public static final String OPTION_COMPONENT_API_DIR = "compAPIDir";
public static final String OPTION_XSL = "xsl";
private String compDirLoc;
private String compApiDirLoc;
private Map compName2Comp;
private Map comp2Pkgs;
private String xsl;
public APIViolationEmitter(String compDirLoc, String compApiDirLoc)
{
this.compDirLoc = EmitterUtils.addTrailingSeperator(compDirLoc);
this.compApiDirLoc = EmitterUtils.addTrailingSeperator(compApiDirLoc);
compName2Comp = new HashMap();
if (this.compDirLoc != null)
{
File compDir = new File(this.compDirLoc);
if (compDir.exists() && compDir.isDirectory())
EmitterUtils.harvestComponents(compDir, this.compApiDirLoc, compName2Comp);
}
}
public String getXSL()
{
return xsl;
}
public void setXSL(String xsl)
{
this.xsl = xsl;
}
public void setComponents(Map compName2Comp)
{
this.compName2Comp = compName2Comp;
}
public void genAPIViolationReport() throws IOException
{
for (Iterator it = compName2Comp.values().iterator(); it.hasNext();)
cachePkgs((Component)it.next());
for (Iterator it = compName2Comp.keySet().iterator(); it.hasNext();)
genAPIViolationReport((String)it.next());
saveIndexHTML(compApiDirLoc + "index.html");
}
public void genAPIViolationReport(String compName) throws IOException
{
Component comp = (Component)compName2Comp.get(compName);
if (comp != null)
{
ComponentUseType compUse = comp.getCompUseXML();
if (compUse != null)
{
validateComponentUse(comp, compUse, true);
comp.setCompApiXml(null);
List compRefs = new Vector();
ComponentType compType = comp.getCompXML();
ComponentDependsType depends = compType.getComponentDepends();
if (depends == null || depends.isUnrestricted())
compRefs.addAll(compName2Comp.values());
else
{
EList refs = depends.getComponentRef();
for (Iterator it = refs.iterator(); it.hasNext();)
{
ComponentRefType ref = (ComponentRefType)it.next();
Component compRef = (Component)compName2Comp.get(ref.getName());
if (compRef != null)
compRefs.add(compRef);
}
}
for (Iterator it = compRefs.iterator(); it.hasNext();)
{
Component compRef = (Component)it.next();
validateComponentUse(compRef, compUse, false);
compRef.setCompApiXml(null);
}
System.out.println("Writing component-violation.xml for " + compName);
String compViolationXML = comp.getCompApiLoc() + Component.CONST_COMPONENT_VIOLATION_XML;
saveAPIViolations(compUse, new File(compViolationXML));
addToIndexHTML(compName, compViolationXML.substring(compApiDirLoc.length()), compUse);
}
compUse = null;
comp.setCompUseXML(null);
}
}
private void cachePkgs(Component comp)
{
if (comp2Pkgs == null)
comp2Pkgs = new HashMap();
ComponentApiType compApi = comp.getCompApiXml();
ApiTypes apis = compApi.getExternalApis();
EList pkgs = apis.getPackage();
List pkgNames = new Vector(pkgs.size());
for (Iterator it = pkgs.iterator(); it.hasNext();)
pkgNames.add(((Package)it.next()).getName());
comp.setCompApiXml(null);
comp2Pkgs.put(comp, pkgNames);
}
private boolean hasMatchingPkg(Component comp, EList sources)
{
for (int i = 0; i < sources.size(); i++)
{
SourceClass source = (SourceClass)sources.get(i);
EList classUses = source.getClassUse();
for (int j = 0; j < classUses.size(); j++)
{
ClassApi classUse = (ClassApi)classUses.get(j);
String classUseName = classUse.getName();
List pkgNames = (List)comp2Pkgs.get(comp);
if (pkgNames != null)
for (Iterator pkgNamesIt = pkgNames.iterator(); pkgNamesIt.hasNext();)
if (classUseName.startsWith((String)pkgNamesIt.next()))
return true;
}
}
return false;
}
private void validateComponentUse(Component comp, ComponentUseType compUse, boolean useInternalApis)
{
EList sources = compUse.getSourceClass();
if (!useInternalApis && !hasMatchingPkg(comp, sources))
return;
for (int i = 0; i < sources.size(); i++)
{
SourceClass source = (SourceClass)sources.get(i);
EList classUses = source.getClassUse();
for (int j = 0; j < classUses.size(); j++)
{
ClassApi classUse = (ClassApi)classUses.get(j);
String classUseName = classUse.getName();
boolean foundApi = false;
ComponentApiType compApi = comp.getCompApiXml();
ApiTypes apis = useInternalApis ? compApi.getInternalApis() : compApi.getExternalApis();
EList pkgs = apis.getPackage();
for (Iterator pkgsIt = pkgs.iterator(); pkgsIt.hasNext();)
{
Package pkg = (Package)pkgsIt.next();
if (classUseName.startsWith(pkg.getName()))
{
EList classApis = pkg.getClassApi();
for (Iterator classApisIt = classApis.iterator(); classApisIt.hasNext();)
{
ClassApi classApi = (ClassApi)classApisIt.next();
if (classUseName.equals(classApi.getName()))
{
if (useInternalApis)
foundApi = true;
else
{
if (!classUse.isReference() || classApi.isReference())
if (!classUse.isSubclass() || classApi.isSubclass())
if (!classUse.isImplement() || classApi.isImplement())
if (!classUse.isInstantiate() || classApi.isInstantiate())
foundApi = true;
}
if (foundApi)
{
classUses.remove(j);
j--;
break;
}
}
}
}
if (foundApi)
break;
}
}
if (classUses.size() == 0)
{
sources.remove(i);
i--;
}
}
comp.setCompApiXml(null);
}
private MethodApi getAPIViolation(ClassApi classApi, MethodApi methodUse)
{
String name = methodUse.getName();
List params = methodUse.getInputType();
String returnType = methodUse.getReturnType();
EList methodApis = classApi.getMethodApi();
for (Iterator it = methodApis.iterator(); it.hasNext();)
{
MethodApi methodApi = (MethodApi)it.next();
if (methodApi.getName().equals(name) && inputTypeEquals(methodApi.getInputType(), params) && methodApi.getReturnType().equals(returnType))
return null;
}
return clone(methodUse);
}
private FieldApi getAPIViolation(ClassApi classApi, FieldApi fieldUse)
{
String name = fieldUse.getName();
String type = fieldUse.getType();
EList fieldApis = classApi.getFieldApi();
for (Iterator it = fieldApis.iterator(); it.hasNext();)
{
FieldApi fieldApi = (FieldApi)it.next();
if (fieldApi.getName().equals(name) && fieldApi.getType().equals(type))
return null;
}
return clone(fieldUse);
}
private boolean inputTypeEquals(List api, List use)
{
if (api.size() == use.size())
{
int size = api.size();
for (int i = 0; i < size; i++)
if (!api.get(i).equals(use.get(i)))
return false;
return true;
}
return false;
}
private SourceClass clone(SourceClass sourceClass)
{
SourceClass newSourceClass = UseFactory.eINSTANCE.createSourceClass();
newSourceClass.setName(sourceClass.getName());
return newSourceClass;
}
private ClassApi clone(ClassApi classApi)
{
ClassApi classApiClone = ApiFactory.eINSTANCE.createClassApi();
classApiClone.setName(classApi.getName());
classApiClone.setReference(classApi.isReference());
classApiClone.setSubclass(classApi.isSubclass());
classApiClone.setImplement(classApi.isImplement());
classApiClone.setInstantiate(classApi.isInstantiate());
return classApiClone;
}
private MethodApi clone(MethodApi methodApi)
{
MethodApi methodUseClone = ApiFactory.eINSTANCE.createMethodApi();
methodUseClone.setName(methodApi.getName());
methodUseClone.setInputType(methodApi.getInputType());
methodUseClone.setReturnType(methodApi.getReturnType());
return methodUseClone;
}
private FieldApi clone(FieldApi fieldApi)
{
FieldApi fieldUseClone = ApiFactory.eINSTANCE.createFieldApi();
fieldUseClone.setName(fieldApi.getName());
fieldUseClone.setType(fieldApi.getType());
return fieldUseClone;
}
private ClassApi deepClone(ClassApi classApi)
{
ClassApi classApiClone = clone(classApi);
for (Iterator it = classApi.getMethodApi().iterator(); it.hasNext();)
classApiClone.getMethodApi().add(clone((MethodApi)it.next()));
for (Iterator it = classApi.getFieldApi().iterator(); it.hasNext();)
classApiClone.getFieldApi().add(clone((FieldApi)it.next()));
return classApiClone;
}
private void saveAPIViolations(ComponentUseType apiViolations, File file) throws IOException
{
file.getParentFile().mkdirs();
ResourceSet res = new ResourceSetImpl();
res.getResourceFactoryRegistry().getExtensionToFactoryMap().put("componentviolation", new UseResourceFactoryImpl());
res.getPackageRegistry().put(UsePackage.eNS_URI, UsePackage.eINSTANCE);
UseResourceImpl useRes = (UseResourceImpl)res.createResource(URI.createURI("*.componentviolation"));
org.eclipse.wtp.releng.tools.component.use.DocumentRoot root = UseFactory.eINSTANCE.createDocumentRoot();
root.setComponentUse(apiViolations);
useRes.getContents().add(root);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
useRes.save(baos, new HashMap());
if (xsl != null)
{
byte[] b = baos.toByteArray();
for (int i = 0; i < b.length; i++)
{
if (b[i] == '>')
{
String violationPath = file.getParentFile().getAbsolutePath().replace('\\', '/');
String xslPath = xsl.replace('\\', '/');
int violationPathLen = violationPath.length();
int xslPathLen = xslPath.length();
int index = 0;
while (violationPathLen > index && xslPathLen > index && violationPath.charAt(index) == xslPath.charAt(index))
index++;
StringTokenizer violationPathST = new StringTokenizer(violationPath.substring(index), "/");
StringBuffer sb = new StringBuffer("<?xml-stylesheet type=\"text/xsl\" href=\"");
int tokenCount = violationPathST.countTokens();
for (int j = 0; j < tokenCount; j++)
sb.append("../");
sb.append(xslPath.substring(index));
sb.append("\"?>");
byte[] bCopy = new byte[b.length + sb.length()];
System.arraycopy(b, 0, bCopy, 0, i + 1);
System.arraycopy(sb.toString().getBytes(), 0, bCopy, i + 1, sb.length());
System.arraycopy(b, i + 1, bCopy, i + 1 + sb.length(), b.length - i - 1);
baos = new ByteArrayOutputStream();
baos.write(bCopy);
break;
}
}
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
baos.writeTo(bos);
bos.close();
}
private StringBuffer indexHTML;
private void addToIndexHTML(String compName, String compViolationXML, ComponentUseType compUse)
{
int violations = 0;
EList source = compUse.getSourceClass();
for (Iterator it = source.iterator(); it.hasNext();)
violations += ((SourceClass)it.next()).getClassUse().size();
if (indexHTML == null)
indexHTML = new StringBuffer("<html><bod><table><th>Component</th><th>Violations</th>");
indexHTML.append("<tr><td><a href=\"");
indexHTML.append(compViolationXML);
indexHTML.append("\">");
indexHTML.append(compName);
indexHTML.append("</a></td><td>");
indexHTML.append(String.valueOf(violations));
indexHTML.append("</td></tr>");
}
private void saveIndexHTML(String loc) throws IOException
{
indexHTML.append("</table></body></html>");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(loc));
bos.write(indexHTML.toString().getBytes());
bos.close();
}
public static void main(String[] args)
{
CommandOptionParser optionParser = new CommandOptionParser(args);
Map options = optionParser.getOptions();
List compDir = (List)options.get(APIViolationEmitter.OPTION_COMPONENT_DIR);
List compAPIDir = (List)options.get(APIViolationEmitter.OPTION_COMPONENT_API_DIR);
List xsl = (List)options.get(APIViolationEmitter.OPTION_XSL);
if (compDir == null || compAPIDir == null || compDir.size() < 1 || compAPIDir.size() < 1)
{
printUsage();
System.exit(-1);
}
APIViolationEmitter apiViolationEmitter = new APIViolationEmitter((String)compDir.get(0), (String)compAPIDir.get(0));
if (xsl != null && xsl.size() > 0)
apiViolationEmitter.setXSL((String)xsl.get(0));
try
{
apiViolationEmitter.genAPIViolationReport();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
private static void printUsage()
{
System.out.println("Usage: java -compDir <compDir> -compAPIDir <compAPIDir> -xsd <xsd> org.eclipse.wtp.releng.tools.component.APIViolationEmitter");
System.out.println("");
System.out.println("\t-compDir\tdirectory containing component.xml");
System.out.println("\t-compAPIDir\toutput directory of component-api.xml and component-use.xml");
System.out.println("\t-xsl\tlocaiton of the XSL stylesheet");
}
}