| /********************************************************************** |
| * 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.MissingResourceException; |
| import java.util.ResourceBundle; |
| 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.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 |
| { |
| private String compDirLoc; |
| private Map compName2Comp; |
| private Map comp2Pkgs; |
| private String xsl; |
| |
| public APIViolationEmitter(String compDirLoc) |
| { |
| this.compDirLoc = compDirLoc; |
| compName2Comp = new HashMap(); |
| if (compDirLoc != null) |
| { |
| File compDir = new File(compDirLoc); |
| if (compDir.exists() && compDir.isDirectory()) |
| EmitterUtils.harvestComponents(compDir, compName2Comp); |
| } |
| init(); |
| } |
| |
| private void init() |
| { |
| try |
| { |
| ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.wtp.releng.tools.component.component"); |
| StringBuffer sb = new StringBuffer(); |
| sb.append("<?xml-stylesheet type=\"text/xsl\" href=\""); |
| sb.append(bundle.getString("component-violation-xsl")); |
| sb.append("\"?>"); |
| xsl = sb.toString(); |
| } |
| catch (MissingResourceException mre) |
| { |
| mre.printStackTrace(); |
| } |
| } |
| |
| 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()); |
| } |
| |
| 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); |
| saveAPIViolations(compUse, new File(comp.getCompLoc() + Component.CONST_COMPONENT_VIOLATION_XML)); |
| } |
| 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 |
| { |
| 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] == '>') |
| { |
| byte[] bCopy = new byte[b.length + xsl.length()]; |
| System.arraycopy(b, 0, bCopy, 0, i + 1); |
| System.arraycopy(xsl.getBytes(), 0, bCopy, i + 1, xsl.length()); |
| System.arraycopy(b, i + 1, bCopy, i + 1 + xsl.length(), b.length - i - 1); |
| baos = new ByteArrayOutputStream(); |
| baos.write(bCopy); |
| break; |
| } |
| } |
| } |
| BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); |
| baos.writeTo(bos); |
| bos.close(); |
| } |
| } |