| /********************************************************************** |
| * 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.api; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import org.eclipse.wtp.releng.tools.component.IClazz; |
| import org.eclipse.wtp.releng.tools.component.IClazzVisitor; |
| import org.eclipse.wtp.releng.tools.component.ILocation; |
| import org.eclipse.wtp.releng.tools.component.IPluginXML; |
| import org.eclipse.wtp.releng.tools.component.internal.AbstractEmitter; |
| 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.Plugin; |
| import org.eclipse.wtp.releng.tools.component.model.Type; |
| import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser; |
| import org.eclipse.jdt.core.util.IExceptionAttribute; |
| import org.eclipse.jdt.core.util.IFieldInfo; |
| import org.eclipse.jdt.core.util.IMethodInfo; |
| import org.eclipse.jdt.core.util.IModifierConstants; |
| |
| public class ComponentAPIEmitter extends AbstractEmitter implements IClazzVisitor |
| { |
| public static final String OPTION_ECLIPSE_DIR = "eclipseDir"; |
| public static final String OPTION_COMPONENT_XML_DIR = "compXMLDir"; |
| public static final String OPTION_COMPONENT_API_DIR = "compAPIDir"; |
| private String compAPIDir; |
| private boolean genInternalAPIs; |
| private boolean noFieldAPIs; |
| private Map compLoc2CompXML; |
| private Map pluginId2Plugin; |
| private Map fragmentId2Fragment; |
| private ComponentXML compXML; |
| private ComponentAPI compAPI; |
| |
| public ComponentAPIEmitter(String compAPIDir) |
| { |
| this.compAPIDir = addTrailingSeperator(compAPIDir); |
| genInternalAPIs = false; |
| noFieldAPIs = false; |
| } |
| |
| public void init(List eclipseDirs, List compXMLDirs) |
| { |
| compLoc2CompXML = 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); |
| } |
| } |
| |
| public void init(Map compLoc2CompXML, Map pluginId2Plugin, Map fragmentId2Fragment) |
| { |
| this.compLoc2CompXML = compLoc2CompXML; |
| this.pluginId2Plugin = pluginId2Plugin; |
| this.fragmentId2Fragment = fragmentId2Fragment; |
| } |
| |
| public boolean getNoFieldAPIs() |
| { |
| return noFieldAPIs; |
| } |
| |
| public void setNoFieldAPIs(boolean noFieldAPIs) |
| { |
| this.noFieldAPIs = noFieldAPIs; |
| } |
| |
| public void genComponentApiXml() throws IOException |
| { |
| for (Iterator it = compLoc2CompXML.keySet().iterator(); it.hasNext();) |
| genComponentApiXml((String)it.next()); |
| } |
| |
| public ComponentAPI genComponentApiXml(String compLoc) throws IOException |
| { |
| compXML = (ComponentXML)compLoc2CompXML.get(compLoc); |
| if (compXML != null) |
| { |
| compXML.load(); |
| String compName = compXML.getName(); |
| compAPI = newComponentAPI(compXML); |
| for (Iterator pluginsIt = compXML.getPlugins().iterator(); pluginsIt.hasNext();) |
| { |
| IPluginXML plugin = (IPluginXML)pluginId2Plugin.get(((Plugin)pluginsIt.next()).getId()); |
| if (plugin != null) |
| plugin.accept(this); |
| } |
| compXML = null; |
| if (compAPIDir != null) |
| System.out.println("Writing component-api.xml for " + compName); |
| compAPI.save(); |
| return compAPI; |
| } |
| return null; |
| } |
| |
| public boolean visit(IClazz clazz) |
| { |
| if (compXML == null || compAPI == null) |
| return false; |
| ClassAPI classAPI = addClassAPI(compXML, clazz, compAPI); |
| if (classAPI != null) |
| { |
| IMethodInfo[] methodInfos = clazz.getMethodInfo(); |
| for (int i = 0; i < methodInfos.length; i++) |
| { |
| int access = methodInfos[i].getAccessFlags(); |
| if (!isBit(access, IModifierConstants.ACC_PRIVATE)) |
| { |
| String[] exs = new String[0]; |
| IExceptionAttribute exAttr = methodInfos[i].getExceptionAttribute(); |
| if (exAttr != null) |
| { |
| char[][] exChars = exAttr.getExceptionNames(); |
| exs = new String[exChars.length]; |
| for (int j = 0; j < exs.length; j++) |
| exs[j] = decodeClassName(new String(exChars[j])); |
| } |
| addMethodAPI(classAPI, newMethodAPI(new String(methodInfos[i].getName()), access, new String(methodInfos[i].getDescriptor()), exs)); |
| } |
| } |
| if (!noFieldAPIs) |
| { |
| IFieldInfo[] fieldInfos = clazz.getFieldInfo(); |
| for (int i = 0; i < fieldInfos.length; i++) |
| { |
| int access = fieldInfos[i].getAccessFlags(); |
| if (!isBit(access, IModifierConstants.ACC_PRIVATE)) |
| { |
| addFieldAPI(classAPI, newFieldAPI(new String(fieldInfos[i].getName()), access, new String(fieldInfos[i].getDescriptor()))); |
| } |
| } |
| } |
| } |
| return true; |
| } |
| |
| private ClassAPI addClassAPI(ComponentXML compXML, IClazz clazz, ComponentAPI compAPI) |
| { |
| String typeName = clazz.getName(); |
| int index = typeName.lastIndexOf('.'); |
| String pkgName; |
| String localName; |
| if (index != -1) |
| { |
| pkgName = typeName.substring(0, index); |
| localName = typeName.substring(index + 1); |
| } |
| else |
| { |
| pkgName = ""; |
| localName = typeName; |
| } |
| if (genInternalAPIs) |
| { |
| ClassAPI internalClassAPI = new ClassAPI(); |
| internalClassAPI.setName(typeName); |
| addClassAPI(compAPI, true, pkgName, internalClassAPI); |
| } |
| if (!isBit(clazz.getAccessFlags(), IModifierConstants.ACC_PRIVATE)) |
| { |
| boolean isInterface = clazz.isInterface(); |
| Package pkg = findPackage(compXML, pkgName); |
| if (pkg != null) |
| { |
| Type type = findType(pkg, localName); |
| if (type != null) |
| { |
| boolean ref = type.isReference(); |
| boolean subclass = type.isSubclass() && !isInterface; |
| boolean implement = type.isImplement() && isInterface; |
| boolean instantiate = type.isInstantiate() && !isInterface; |
| if (ref || subclass || implement || instantiate) |
| { |
| // at least one public usage |
| ClassAPI externalClassAPI = newClassAPI(typeName, clazz.getAccessFlags(), new Boolean(ref), new Boolean(subclass), new Boolean(implement), new Boolean(instantiate)); |
| addClassAPI(compAPI, false, pkgName, externalClassAPI); |
| return externalClassAPI; |
| } |
| else |
| { |
| // all usage are set to false, in another word, it is an internal API |
| return null; |
| } |
| } |
| else if (pkg.isApi()) |
| { |
| // api == true means, by default, a non-listed type is an external API |
| ClassAPI externalClassAPI = newClassAPI(typeName, clazz.getAccessFlags(), Boolean.TRUE, new Boolean(!isInterface), new Boolean(isInterface), new Boolean(!isInterface)); |
| addClassAPI(compAPI, false, pkgName, externalClassAPI); |
| return externalClassAPI; |
| } |
| else |
| { |
| // api == false means, by default, a non-listed type is an internal API |
| return null; |
| } |
| } |
| else |
| { |
| // package not defined in component.xml means it is an internal API |
| return null; |
| } |
| } |
| return null; |
| } |
| |
| private void addClassAPI(ComponentAPI compAPI, boolean isInternal, String pkgName, ClassAPI classAPI) |
| { |
| APIs apis = (isInternal) ? compAPI.getInternalAPIs() : compAPI.getExternalAPIs(); |
| List pkgAPIs = apis.getPackageAPIs(); |
| PackageAPI pkgAPI = null; |
| for (Iterator it = pkgAPIs.iterator(); it.hasNext();) |
| { |
| PackageAPI nextPkg = (PackageAPI)it.next(); |
| if (nextPkg.getName().equals(pkgName)) |
| { |
| pkgAPI = nextPkg; |
| break; |
| } |
| } |
| if (pkgAPI == null) |
| { |
| pkgAPI = newPackageAPI(pkgName); |
| pkgAPIs.add(pkgAPI); |
| } |
| pkgAPI.getClassAPIs().add(classAPI); |
| } |
| |
| private void addMethodAPI(ClassAPI classAPI, MethodAPI methodAPI) |
| { |
| classAPI.getMethodAPIs().add(methodAPI); |
| } |
| |
| private void addFieldAPI(ClassAPI classAPI, FieldAPI fieldAPI) |
| { |
| classAPI.getFieldAPIs().add(fieldAPI); |
| } |
| |
| private PackageAPI newPackageAPI(String pkgName) |
| { |
| PackageAPI pkg = new PackageAPI(); |
| pkg.setName(pkgName); |
| return pkg; |
| } |
| |
| private ComponentAPI newComponentAPI(ComponentXML compXML) |
| { |
| String compName = compXML.getName(); |
| ILocation location = null; |
| if (compAPIDir != null) |
| { |
| StringBuffer sb = new StringBuffer(compAPIDir); |
| sb.append(compName); |
| sb.append('/'); |
| sb.append(ComponentAPI.CONST_COMPONENT_API_XML); |
| location = new FileLocation(new File(sb.toString())); |
| } |
| return newComponentAPI(compName, location); |
| } |
| |
| private ComponentAPI newComponentAPI(String compName, ILocation location) |
| { |
| ComponentAPI compAPI = new ComponentAPI(); |
| compAPI.setName(compName); |
| compAPI.setLocation(location); |
| return compAPI; |
| } |
| private ClassAPI newClassAPI(String className, int access, Boolean ref, Boolean subclass, Boolean implement, Boolean instantiate) |
| { |
| ClassAPI classAPI = new ClassAPI(); |
| classAPI.setName(className); |
| classAPI.setAccess(access); |
| classAPI.setReference(ref); |
| classAPI.setSubclass(subclass); |
| classAPI.setImplement(implement); |
| classAPI.setInstantiate(instantiate); |
| return classAPI; |
| } |
| |
| private MethodAPI newMethodAPI(String methodName, int access, String descriptor, String[] throwTypes) |
| { |
| MethodAPI methodAPI = new MethodAPI(); |
| methodAPI.setName(methodName); |
| methodAPI.setAccess(access); |
| methodAPI.setDescriptor(descriptor); |
| List throwList = methodAPI.getThrows(); |
| for (int i = 0; i < throwTypes.length; i++) |
| throwList.add(throwTypes[i]); |
| return methodAPI; |
| } |
| |
| private FieldAPI newFieldAPI(String fieldName, int access, String descriptor) |
| { |
| FieldAPI fieldAPI = new FieldAPI(); |
| fieldAPI.setName(fieldName); |
| fieldAPI.setAccess(access); |
| fieldAPI.setDescriptor(descriptor); |
| return fieldAPI; |
| } |
| |
| private Package findPackage(ComponentXML compXML, String pkgName) |
| { |
| if (pkgName != null && compXML != null) |
| { |
| List pkgs = compXML.getPackages(); |
| for (Iterator it = pkgs.iterator(); it.hasNext();) |
| { |
| Package pkg = (Package)it.next(); |
| if (pkgName.equals(pkg.getName())) |
| return pkg; |
| } |
| } |
| return null; |
| } |
| |
| private Type findType(Package pkg, String typeName) |
| { |
| if (typeName != null) |
| { |
| List types = pkg.getTypes(); |
| for (Iterator it = types.iterator(); it.hasNext();) |
| { |
| Type type = (Type)it.next(); |
| if (typeName.equals(type.getName())) |
| return type; |
| } |
| } |
| return null; |
| } |
| |
| private boolean isBit(int flag, int bit) |
| { |
| return ((flag & bit) == bit); |
| } |
| |
| public static void main(String[] args) |
| { |
| CommandOptionParser optionParser = new CommandOptionParser(args); |
| Map options = optionParser.getOptions(); |
| List eclipseDir = (List)options.get(ComponentAPIEmitter.OPTION_ECLIPSE_DIR); |
| List compXMLDir = (List)options.get(ComponentAPIEmitter.OPTION_COMPONENT_XML_DIR); |
| List compAPIDir = (List)options.get(ComponentAPIEmitter.OPTION_COMPONENT_API_DIR); |
| if (eclipseDir == null || compXMLDir == null || compAPIDir == null || eclipseDir.size() < 1 || compXMLDir.size() < 1 || compAPIDir.size() < 1) |
| { |
| printUsage(); |
| System.exit(-1); |
| } |
| ComponentAPIEmitter compAPIEmitter = new ComponentAPIEmitter((String)compAPIDir.get(0)); |
| compAPIEmitter.init(eclipseDir, compXMLDir); |
| try |
| { |
| compAPIEmitter.genComponentApiXml(); |
| } |
| catch (IOException ioe) |
| { |
| ioe.printStackTrace(); |
| } |
| } |
| |
| private static void printUsage() |
| { |
| System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.api.ComponentAPIEmitter -eclipseDir <eclipseDir> -compXMLDir <compDir> -compAPIDir <compAPIDir> [-options]"); |
| System.out.println(""); |
| System.out.println("\t-eclipseDir\t<eclipseDir>\tspace seperated list of directories containing Eclipse plugins"); |
| System.out.println("\t-compXMLDir\t<compXMLDir>\tdirectory containing component.xml"); |
| System.out.println("\t-compAPIDir\t<compAPIDir>\toutput directory of component-api.xml"); |
| } |
| } |