blob: 0876106ca2c8a56dc03213b3edf227c8659bd6c3 [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.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");
}
}