| /******************************************************************************* |
| * 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.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.parsers.SAXParser; |
| import javax.xml.parsers.SAXParserFactory; |
| import org.eclipse.core.runtime.IPlatformRunnable; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jdt.core.util.IModifierConstants; |
| import org.eclipse.wtp.releng.tools.component.ILocation; |
| import org.eclipse.wtp.releng.tools.component.ILocationVisitor; |
| import org.eclipse.wtp.releng.tools.component.api.API2ComponentAPI; |
| 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.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.Location; |
| import org.eclipse.wtp.releng.tools.component.java.Java2API; |
| import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser; |
| import org.eclipse.wtp.releng.tools.component.xsl.XSLUtil; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| public class APIRefCompatibilityScanner implements IPlatformRunnable |
| { |
| private String src; |
| private String use; |
| private String outputDir; |
| |
| public String getOutputDir() |
| { |
| return outputDir; |
| } |
| |
| public void setOutputDir(String outputDir) |
| { |
| this.outputDir = addTrailingSeperator(outputDir); |
| } |
| |
| public String getSrc() |
| { |
| return src; |
| } |
| |
| public void setSrc(String src) |
| { |
| this.src = src; |
| } |
| |
| public String getUse() |
| { |
| return use; |
| } |
| |
| public void setUse(String use) |
| { |
| this.use = use; |
| } |
| private Map pkg2APIInfo = new HashMap(); |
| private References refs = new References(); |
| |
| public void execute() |
| { |
| ILocation apiInfoLoc = Location.createLocation(new File(outputDir + "_tmp_componentapi")); |
| apiInfoLoc.accept(new ILocationVisitor() |
| { |
| public boolean accept(ILocation location) |
| { |
| if (location.getName().endsWith("api-info.xml")) |
| { |
| ComponentAPI compAPI = new ComponentAPI(); |
| compAPI.setLocation(location); |
| try |
| { |
| compAPI.load(); |
| for (Iterator it = compAPI.getPackageAPIs().iterator(); it.hasNext();) |
| { |
| String pkgName = ((PackageAPI)it.next()).getName(); |
| List locations = (List)pkg2APIInfo.get(pkgName); |
| if (locations == null) |
| { |
| locations = new ArrayList(); |
| pkg2APIInfo.put(pkgName, locations); |
| } |
| locations.add(location); |
| } |
| } |
| catch (IOException ioe) |
| { |
| throw new RuntimeException(ioe); |
| } |
| } |
| return true; |
| } |
| }); |
| ILocation useLoc = Location.createLocation(new File(use)); |
| useLoc.accept(new ILocationVisitor() |
| { |
| public boolean accept(ILocation location) |
| { |
| if (location.getName().endsWith(".xml")) |
| { |
| try |
| { |
| SAXParserFactory factory = SAXParserFactory.newInstance(); |
| factory.setNamespaceAware(false); |
| factory.setValidating(false); |
| SAXParser parser = factory.newSAXParser(); |
| parser.parse(new InputSource(location.getInputStream()), new APIRefHandler(refs)); |
| } |
| catch (ParserConfigurationException pce) |
| { |
| throw new RuntimeException(pce); |
| } |
| catch (SAXException saxe) |
| { |
| throw new RuntimeException(saxe); |
| } |
| catch (IOException ioe) |
| { |
| throw new RuntimeException(ioe); |
| } |
| } |
| return true; |
| } |
| }); |
| try |
| { |
| save(); |
| genHTML(); |
| } |
| catch (IOException ioe) |
| { |
| throw new RuntimeException(ioe); |
| } |
| } |
| |
| public void save() throws IOException |
| { |
| File file = new File(outputDir + "api-ref-compatibility.xml"); |
| file.getParentFile().mkdirs(); |
| FileOutputStream fos = new FileOutputStream(file); |
| fos.write(refs.toString().getBytes()); |
| fos.close(); |
| } |
| |
| private void genHTML() |
| { |
| try |
| { |
| XSLUtil.transform(Platform.getBundle("org.eclipse.wtp.releng.tools.component.core").getResource("org/eclipse/wtp/releng/tools/component/xsl/api-ref-compatibility.xsl").openStream(), new ByteArrayInputStream(refs.toString().getBytes()), new FileOutputStream(new File(outputDir + "api-ref-compatibility.html")), outputDir); |
| } |
| catch (Throwable e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| 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; |
| } |
| } |
| protected class APIRefHandler extends DefaultHandler |
| { |
| private References refs; |
| private ClassRef currClassRef; |
| private ClassAPI currClassAPI; |
| |
| public APIRefHandler(References refs) |
| { |
| this.refs = refs; |
| } |
| |
| public void startElement(String uri, String elementName, String qName, Attributes attributes) throws SAXException |
| { |
| if (elementName.equals("class") || qName.equals("class")) |
| { |
| String className = attributes.getValue("name"); |
| if (className.endsWith("[]")) |
| className = className.substring(0, className.length() - 2); |
| int refCount = Integer.parseInt(attributes.getValue("ref")); |
| int subclassCount = Integer.parseInt(attributes.getValue("subclass")); |
| int implCount = Integer.parseInt(attributes.getValue("impl")); |
| int instantiateCount = Integer.parseInt(attributes.getValue("instantiate")); |
| currClassRef = new ClassRef(); |
| currClassRef.setName(className); |
| currClassRef.setRefCount(refCount); |
| currClassRef.setSubclassCount(subclassCount); |
| currClassRef.setImplementCount(implCount); |
| currClassRef.setInstantiateCount(instantiateCount); |
| int i = className.lastIndexOf('.'); |
| String pkgName = (i != -1) ? className.substring(0, i) : ""; |
| String localName = (i != -1) ? className.substring(i + 1) : className; |
| List locations = (List)pkg2APIInfo.get(pkgName); |
| if (locations != null) |
| { |
| for (Iterator it = locations.iterator(); it.hasNext();) |
| { |
| ILocation location = (ILocation)it.next(); |
| try |
| { |
| ComponentAPI compAPI = getComponentAPI(location); |
| if (compAPI != null) |
| { |
| PackageAPI pkgAPI = compAPI.getPackageAPI(pkgName); |
| if (pkgAPI != null) |
| { |
| ClassAPI classAPI = pkgAPI.getClassAPI(localName); |
| if (classAPI != null) |
| { |
| currClassAPI = classAPI; |
| return; |
| } |
| } |
| } |
| } |
| catch (IOException ioe) |
| { |
| ioe.printStackTrace(); |
| } |
| // use reflection, needed for java.* packages |
| currClassAPI = loadClass(className); |
| } |
| // TODO: refs.addClassRef(currClassRef); |
| } |
| } |
| else if (elementName.equals("method") || qName.equals("method")) |
| { |
| String name = attributes.getValue("name"); |
| String desc = attributes.getValue("desc"); |
| if (hasMethod(currClassAPI, name, desc)) |
| return; |
| int refCount2 = Integer.parseInt(attributes.getValue("ref")); |
| // TODO: if (refs.getClassRef(currClassRef.getName()) == null) |
| // TODO: refs.addClassRef(currClassRef); |
| MethodRef methodRef = new MethodRef(); |
| methodRef.setName(name); |
| methodRef.setDescriptor(desc); |
| methodRef.setRefCount(refCount2); |
| currClassRef.addMethodRef(methodRef); |
| } |
| else if (elementName.equals("field") || qName.equals("field")) |
| { |
| String name = attributes.getValue("name"); |
| if (hasField(currClassAPI, name)) |
| return; |
| String desc = attributes.getValue("desc"); |
| int refCount2 = Integer.parseInt(attributes.getValue("ref")); |
| // TODO: if (refs.getClassRef(currClassRef.getName()) == null) |
| // TODO: refs.addClassRef(currClassRef); |
| FieldRef fieldRef = new FieldRef(); |
| fieldRef.setName(name); |
| fieldRef.setDescriptor(desc); |
| fieldRef.setRefCount(refCount2); |
| currClassRef.addFieldRef(fieldRef); |
| } |
| } |
| |
| public void endElement(String uri, String elementName, String qName, Attributes attributes) throws SAXException |
| { |
| if (elementName.equals("class") || qName.equals("class")) |
| { |
| currClassAPI = null; |
| currClassRef = null; |
| } |
| } |
| private int cacheSize = 20; |
| private List cachedIds = new ArrayList(cacheSize); |
| private List cachedCompAPIs = new ArrayList(cacheSize); |
| |
| private ComponentAPI getComponentAPI(ILocation location) throws IOException |
| { |
| int index = cachedIds.indexOf(location); |
| if (index != -1) |
| { |
| ComponentAPI compAPI = (ComponentAPI)cachedCompAPIs.get(index); |
| if (index != 0) |
| { |
| cachedIds.remove(index); |
| cachedCompAPIs.remove(index); |
| cachedIds.add(0, location); |
| cachedCompAPIs.add(0, compAPI); |
| } |
| return compAPI; |
| } |
| ComponentAPI compAPI = new ComponentAPI(); |
| compAPI.setLocation(location); |
| compAPI.load(); |
| if (cachedCompAPIs.size() == cacheSize) |
| { |
| cachedIds.remove(cacheSize - 1); |
| cachedCompAPIs.remove(cacheSize - 1); |
| } |
| cachedIds.add(0, location); |
| cachedCompAPIs.add(0, compAPI); |
| return compAPI; |
| } |
| |
| private boolean hasMethod(ClassAPI classAPI, String name, String desc) |
| { |
| if (classAPI != null && name != null && desc != null) |
| { |
| if (classAPI.getMethodAPI(name, desc) != null) |
| { |
| return true; |
| } |
| else |
| { |
| String superClassName = classAPI.getSuperClass(); |
| if (hasMethod(superClassName, name, desc)) |
| { |
| return true; |
| } |
| else |
| { |
| for (Iterator it = classAPI.getInterfaces().iterator(); it.hasNext();) |
| { |
| if (hasMethod(it.next().toString(), name, desc)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean hasMethod(String className, String name, String desc) |
| { |
| int i = className.lastIndexOf('.'); |
| String pkgName = (i != -1) ? className.substring(0, i) : ""; |
| String localName = (i != -1) ? className.substring(i + 1) : className; |
| List locations = (List)pkg2APIInfo.get(pkgName); |
| if (locations != null) |
| { |
| for (Iterator it = locations.iterator(); it.hasNext();) |
| { |
| ILocation location = (ILocation)it.next(); |
| // ILocation location = (ILocation)pkg2APIInfo.get(pkgName); |
| // if (location != null) |
| // { |
| try |
| { |
| ComponentAPI compAPI = getComponentAPI(location); |
| if (compAPI != null) |
| { |
| PackageAPI pkgAPI = compAPI.getPackageAPI(pkgName); |
| if (pkgAPI != null) |
| { |
| ClassAPI superClassAPI = pkgAPI.getClassAPI(localName); |
| if (superClassAPI != null) |
| { |
| return hasMethod(superClassAPI, name, desc); |
| } |
| } |
| } |
| } |
| catch (IOException ioe) |
| { |
| ioe.printStackTrace(); |
| } |
| } |
| } |
| else |
| { |
| // use reflection, needed for java.* packages |
| ClassAPI superClassAPI = loadClass(className); |
| if (superClassAPI != null) |
| { |
| return hasMethod(superClassAPI, name, desc); |
| } |
| } |
| return false; |
| } |
| |
| private boolean hasField(ClassAPI classAPI, String name) |
| { |
| if (classAPI != null && name != null) |
| { |
| if (classAPI.getFieldAPI(name) != null) |
| { |
| return true; |
| } |
| else |
| { |
| String superClassName = classAPI.getSuperClass(); |
| if (hasField(superClassName, name)) |
| { |
| return true; |
| } |
| else |
| { |
| for (Iterator it = classAPI.getInterfaces().iterator(); it.hasNext();) |
| { |
| if (hasField(it.next().toString(), name)) |
| { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean hasField(String className, String name) |
| { |
| int i = className.lastIndexOf('.'); |
| String pkgName = (i != -1) ? className.substring(0, i) : ""; |
| String localName = (i != -1) ? className.substring(i + 1) : className; |
| List locations = (List)pkg2APIInfo.get(pkgName); |
| if (locations != null) |
| { |
| for (Iterator it = locations.iterator(); it.hasNext();) |
| { |
| ILocation location = (ILocation)it.next(); |
| // ILocation location = (ILocation)pkg2APIInfo.get(pkgName); |
| // if (location != null) |
| // { |
| try |
| { |
| ComponentAPI compAPI = getComponentAPI(location); |
| if (compAPI != null) |
| { |
| PackageAPI pkgAPI = compAPI.getPackageAPI(pkgName); |
| if (pkgAPI != null) |
| { |
| ClassAPI superClassAPI = pkgAPI.getClassAPI(localName); |
| if (superClassAPI != null) |
| { |
| return hasField(superClassAPI, name); |
| } |
| } |
| } |
| } |
| catch (IOException ioe) |
| { |
| ioe.printStackTrace(); |
| } |
| } |
| } |
| else |
| { |
| // use reflection, needed for java.* packages |
| ClassAPI superClassAPI = loadClass(className); |
| if (superClassAPI != null) |
| { |
| return hasField(superClassAPI, name); |
| } |
| } |
| return false; |
| } |
| |
| private ClassAPI loadClass(String className) |
| { |
| // Use reflection to load other packages |
| try |
| { |
| Class clazz = ClassLoader.getSystemClassLoader().loadClass(className); |
| ClassAPI classAPI = new ClassAPI(); |
| classAPI.setName(className); |
| if (className.equals("java.lang.Object")) |
| classAPI.setSuperClass(""); |
| else |
| classAPI.setSuperClass("java.lang.Object"); |
| // TODO: We need to add protected methods as well |
| Method[] publicMethods = clazz.getMethods(); |
| Field[] publicFields = clazz.getFields(); |
| for (int j = 0; j < publicMethods.length; j++) |
| { |
| MethodAPI methodAPI = new MethodAPI(); |
| methodAPI.setName(publicMethods[j].getName()); |
| StringBuffer descriptor = new StringBuffer(); |
| descriptor.append('('); |
| Class[] params = publicMethods[j].getParameterTypes(); |
| for (int k = 0; k < params.length; k++) |
| { |
| String paramName = params[k].getName().replace('.', '/'); |
| if (paramName.charAt(0) == '[') |
| descriptor.append(paramName); |
| else |
| descriptor.append(Signature.createTypeSignature(paramName, true)); |
| //descriptor.append(params[k].toString()); |
| } |
| descriptor.append(')'); |
| Class returnType = publicMethods[j].getReturnType(); |
| if (returnType != null) |
| { |
| String returnTypeName = returnType.getName().replace('.', '/'); |
| if (returnTypeName.charAt(0) == '[') |
| descriptor.append(returnTypeName); |
| else |
| descriptor.append(Signature.createTypeSignature(returnTypeName, true)); |
| //descriptor.append(returnType.toString()); |
| } |
| else |
| { |
| descriptor.append('V'); |
| } |
| methodAPI.setDescriptor(descriptor.toString()); |
| classAPI.addMethodAPI(methodAPI); |
| } |
| for (int j = 0; j < publicFields.length; j++) |
| { |
| FieldAPI fieldAPI = new FieldAPI(); |
| fieldAPI.setName(publicFields[j].getName()); |
| classAPI.addFieldAPI(fieldAPI); |
| } |
| return classAPI; |
| } |
| catch (ClassNotFoundException cnfe) |
| { |
| return null; |
| // do nothing |
| } |
| } |
| } |
| |
| public Object run(Object arguments) |
| { |
| String src = System.getProperty("src"); |
| String use = System.getProperty("use"); |
| String outputDir = System.getProperty("outputDir"); |
| try |
| { |
| main(new String[]{"-src", src, "-use", use, "-outputDir", outputDir}); |
| } |
| catch (Throwable t) |
| { |
| t.printStackTrace(); |
| } |
| return IPlatformRunnable.EXIT_OK; |
| } |
| |
| public static void main(String[] args) |
| { |
| CommandOptionParser optionParser = new CommandOptionParser(args); |
| Map options = optionParser.getOptions(); |
| Collection src = (Collection)options.get("src"); |
| Collection use = (Collection)options.get("use"); |
| Collection outputDir = (Collection)options.get("outputDir"); |
| if (src == null || use == null || outputDir == null || src.isEmpty() || use.isEmpty() || outputDir.isEmpty()) |
| { |
| printUsage(); |
| System.exit(-1); |
| } |
| String srcString = (String)src.iterator().next(); |
| String outputDirString = addTrailingSeperator((String)outputDir.iterator().next()); |
| String componentxml = outputDirString + "_tmp_componentxml"; |
| String componentapi = outputDirString + "_tmp_componentapi"; |
| |
| List srcs = new ArrayList(); |
| srcs.add(srcString); |
| srcs.add("D:/temp/RAD/eclipse-SDK-3.2M4-win32.zip"); |
| srcs.add("D:/temp/RAD/emf-sdo-xsd-SDK-2.2.0M4.zip"); |
| srcs.add("D:/temp/RAD/GEF-SDK-3.2M4.zip"); |
| srcs.add("D:/temp/RAD/JEM-SDK-1.2M1.zip"); |
| Plugin2API plugin2API = new Plugin2API(); |
| plugin2API.setSrc(srcs); |
| plugin2API.setOutputDir(componentxml); |
| plugin2API.execute(); |
| |
| API2ComponentAPI api2CompAPI = new API2ComponentAPI(); |
| api2CompAPI.setApi(componentxml); |
| api2CompAPI.setSrc(srcString); |
| api2CompAPI.setOutputDir(componentapi); |
| api2CompAPI.setIncludeInnerClass(true); |
| api2CompAPI.setIncludeInterfaces(true); |
| api2CompAPI.execute(); |
| |
| api2CompAPI.setSrc("D:/temp/RAD/eclipse-SDK-3.2M4-win32.zip"); |
| api2CompAPI.execute(); |
| api2CompAPI.setSrc("D:/temp/RAD/emf-sdo-xsd-SDK-2.2.0M4.zip"); |
| api2CompAPI.execute(); |
| api2CompAPI.setSrc("D:/temp/RAD/GEF-SDK-3.2M4.zip"); |
| api2CompAPI.execute(); |
| api2CompAPI.setSrc("D:/temp/RAD/JEM-SDK-1.2M1.zip"); |
| api2CompAPI.execute(); |
| |
| APIRefCompatibilityScanner scanner = new APIRefCompatibilityScanner(); |
| scanner.setSrc((String)src.iterator().next()); |
| scanner.setUse((String)use.iterator().next()); |
| scanner.setOutputDir(outputDirString); |
| scanner.execute(); |
| } |
| |
| private static void printUsage() |
| { |
| System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.adopters.APIRefCompatibilityScanner -src <src> -use <use> -outputDir <outputDir> [-options]"); |
| System.out.println(""); |
| System.out.println("\t-src\t\t<src>\t\tlocation of your Eclipse-based product"); |
| System.out.println("\t-use\t\t<use>\t\tlocation of adopters' API usage data"); |
| System.out.println("\t-outputDir\t<outputDir>\toutput directory"); |
| } |
| } |