blob: 9fb355f24d3b603b1d1a6dc15beeb2d3c5ca25ad [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.component;
import java.io.BufferedOutputStream;
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.Set;
import java.util.Vector;
import org.eclipse.component.internalreference.ConfigurationFileParser;
import org.eclipse.component.internalreference.Fragment;
import org.eclipse.component.internalreference.Library;
import org.eclipse.component.internalreference.Plugin;
import org.eclipse.component.internalreference.Type;
import org.eclipse.component.location.FileLocation;
import org.eclipse.component.use.ComponentUseType;
import org.eclipse.component.use.SourceClass;
import org.eclipse.component.use.UseFactory;
import org.eclipse.component.use.UsePackage;
import org.eclipse.component.use.util.UseResourceFactoryImpl;
import org.eclipse.component.use.util.UseResourceImpl;
import org.eclipse.component.ComponentType;
import org.eclipse.component.PackageType;
import org.eclipse.component.PluginType;
import org.eclipse.component.TypeType;
import org.eclipse.component.api.ApiFactory;
import org.eclipse.component.api.ApiPackage;
import org.eclipse.component.api.ApiTypes;
import org.eclipse.component.api.ClassApi;
import org.eclipse.component.api.ComponentApiType;
import org.eclipse.component.api.FieldApi;
import org.eclipse.component.api.MethodApi;
import org.eclipse.component.api.Package;
import org.eclipse.component.api.Visibility;
import org.eclipse.component.api.util.ApiResourceFactoryImpl;
import org.eclipse.component.api.util.ApiResourceImpl;
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;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.util.IConstantPoolConstant;
import org.eclipse.jdt.core.util.IConstantPoolEntry;
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
{
private String compDirLoc;
private String eclipseDirLoc;
private Map compName2Comp;
private Map pluginId2Plugin;
private Map fragmentId2Fragment;
public ComponentAPIEmitter(String compDirLoc, String eclipseDirLoc)
{
this.compDirLoc = compDirLoc;
this.eclipseDirLoc = eclipseDirLoc;
compName2Comp = new HashMap();
pluginId2Plugin = new HashMap();
fragmentId2Fragment = new HashMap();
File compDir = new File(compDirLoc);
if (compDir.exists() && compDir.isDirectory())
harvestComponents(compDir);
File eclipseDir = new File(eclipseDirLoc);
if (eclipseDir.exists() && eclipseDir.isDirectory())
harvestPlugins(eclipseDir);
linkPluginsAndFragments();
}
private void harvestComponents(File file)
{
if (file.isDirectory())
{
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++)
harvestComponents(files[i]);
}
else if (Component.CONST_COMPONENT_XML.equalsIgnoreCase(file.getName()))
{
String path = file.getAbsolutePath();
Component comp = new Component();
comp.setCompLoc(path.substring(0, path.length() - Component.CONST_COMPONENT_XML.length()));
ComponentType compType = comp.getCompXML();
if (compType != null)
compName2Comp.put(compType.getName(), comp);
}
}
private void harvestPlugins(File file)
{
if (file.isDirectory())
{
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++)
harvestPlugins(files[i]);
}
else if (Plugin.CONST_PLUGIN_XML.equalsIgnoreCase(file.getName()))
{
Plugin plugin = ConfigurationFileParser.getPlugin(new FileLocation(new FileLocation(file.getParentFile()), file.getName()));
pluginId2Plugin.put(plugin.getName(), plugin);
}
else if (Fragment.CONST_FRAGMENT_XML.equalsIgnoreCase(file.getName()))
{
Fragment fragment = ConfigurationFileParser.getFragment(new FileLocation(new FileLocation(file.getParentFile()), file.getName()));
fragmentId2Fragment.put(fragment.getFragmentName(), fragment);
}
}
private void linkPluginsAndFragments()
{
for (Iterator it = fragmentId2Fragment.values().iterator(); it.hasNext();)
{
Fragment fragment = (Fragment)it.next();
fragment.link(pluginId2Plugin);
}
}
public void genComponentApiXml() throws IOException
{
for (Iterator it = compName2Comp.keySet().iterator(); it.hasNext();)
genComponentApiXml((String)it.next());
}
public void genComponentApiXml(String compName) throws IOException
{
Component comp = (Component)compName2Comp.get(compName);
if (comp != null)
{
ComponentApiType compApi = newComponentApiType();
ComponentType compType = comp.getCompXML();
EList plugins = compType.getPlugin();
for (Iterator pluginsIt = plugins.iterator(); pluginsIt.hasNext();)
{
PluginType pluginType = (PluginType)pluginsIt.next();
Plugin plugin = (Plugin)pluginId2Plugin.get(pluginType.getId());
if (plugin != null)
{
List libs = plugin.getLibraries();
for (Iterator libsIt = libs.iterator(); libsIt.hasNext();)
{
Library lib = (Library)libsIt.next();
Map types = lib.getTypes();
for (Iterator typesIt = types.keySet().iterator(); typesIt.hasNext();)
{
String typeName = (String)typesIt.next();
Type type = (Type)types.get(typeName);
ClassApi classApi = addClassApi(compType, type, compApi);
IMethodInfo[] methodInfos = type.getMethodInfo();
for (int i = 0; i < methodInfos.length; i++)
{
int accessFlag = methodInfos[i].getAccessFlags();
Boolean visibility;
if (isBit(accessFlag, IModifierConstants.ACC_PUBLIC))
visibility = Boolean.TRUE;
else if (isBit(accessFlag, IModifierConstants.ACC_PROTECTED))
visibility = Boolean.FALSE;
else
visibility = null;
if (visibility != null)
{
String methodName = new String(methodInfos[i].getName());
boolean isStatic = isBit(accessFlag, IModifierConstants.ACC_STATIC);
boolean isFinal = isBit(accessFlag, IModifierConstants.ACC_FINAL);
boolean isSynchronized = isBit(accessFlag, IModifierConstants.ACC_SYNCHRONIZED);
boolean isNative = isBit(accessFlag, IModifierConstants.ACC_NATIVE);
boolean isAbstract = isBit(accessFlag, IModifierConstants.ACC_ABSTRACT);
boolean isStrict = isBit(accessFlag, IModifierConstants.ACC_STRICT);
char[][] paramChars = Signature.getParameterTypes(methodInfos[i].getDescriptor());
String[] params = new String[paramChars.length];
for (int j = 0; j < params.length; j++)
params[j] = descriptor2Signature(paramChars[j]);
String returnType = descriptor2Signature(Signature.getReturnType(methodInfos[i].getDescriptor()));
IExceptionAttribute exAttr = methodInfos[i].getExceptionAttribute();
String[] exs = new String[0];
if (exAttr != null)
{
char[][] exChars = exAttr.getExceptionNames();
exs = new String[exChars.length];
for (int j = 0; j < exs.length; j++)
exs[j] = toClassName(new String(exChars[j]));
}
addMethodApi(classApi, newMethodApi(methodName, visibility.booleanValue(), isStatic, isFinal, isSynchronized, isNative, isAbstract, isStrict, params, returnType, exs));
}
}
IFieldInfo[] fieldInfos = type.getFieldInfo();
for (int i = 0; i < fieldInfos.length; i++)
{
int accessFlag = fieldInfos[i].getAccessFlags();
Boolean visibility;
if (isBit(accessFlag, IModifierConstants.ACC_PUBLIC))
visibility = Boolean.TRUE;
else if (isBit(accessFlag, IModifierConstants.ACC_PROTECTED))
visibility = Boolean.FALSE;
else
visibility = null;
if (visibility != null)
{
String fieldName = new String(fieldInfos[i].getName());
boolean isStatic = isBit(accessFlag, IModifierConstants.ACC_STATIC);
boolean isFinal = isBit(accessFlag, IModifierConstants.ACC_FINAL);
boolean isVolatile = isBit(accessFlag, IModifierConstants.ACC_VOLATILE);
boolean isTransient = isBit(accessFlag, IModifierConstants.ACC_TRANSIENT);
String fieldType = descriptor2Signature(fieldInfos[i].getDescriptor());
addFieldApi(classApi, newFieldApi(fieldName, visibility.booleanValue(), isStatic, isFinal, isVolatile, isTransient, fieldType));
}
}
}
}
}
}
saveComponentApi(compApi, new File(comp.getCompLoc() + Component.CONST_COMPONENT_API_XML));
comp.setCompApiXml(compApi);
}
}
public void genComponentUseXML() throws IOException
{
for (Iterator it = compName2Comp.keySet().iterator(); it.hasNext();)
genComponentUseXML((String)it.next());
}
public void genComponentUseXML(String compName) throws IOException
{
Component comp = (Component)compName2Comp.get(compName);
if (comp != null)
{
ComponentUseType compUse = newComponentUseType();
ComponentType compType = comp.getCompXML();
EList plugins = compType.getPlugin();
for (Iterator pluginsIt = plugins.iterator(); pluginsIt.hasNext();)
{
PluginType pluginType = (PluginType)pluginsIt.next();
Plugin plugin = (Plugin)pluginId2Plugin.get(pluginType.getId());
if (plugin != null)
{
List libs = plugin.getLibraries();
for (Iterator libsIt = libs.iterator(); libsIt.hasNext();)
{
Library lib = (Library)libsIt.next();
Map types = lib.getTypes();
for (Iterator typesIt = types.keySet().iterator(); typesIt.hasNext();)
{
String typeName = (String)typesIt.next();
Type type = (Type)types.get(typeName);
SourceClass sourceClass = newSourceClass(typeName);
addSourceClass(compUse, sourceClass);
// method references
IConstantPoolEntry[] methodRefs = type.getConstantPoolEntries(IConstantPoolConstant.CONSTANT_Methodref);
IConstantPoolEntry[] intMethodRefs = type.getConstantPoolEntries(IConstantPoolConstant.CONSTANT_InterfaceMethodref);
IConstantPoolEntry[] allMethodRefs = new IConstantPoolEntry[methodRefs.length + intMethodRefs.length];
System.arraycopy(methodRefs, 0, allMethodRefs, 0, methodRefs.length);
System.arraycopy(intMethodRefs, 0, allMethodRefs, methodRefs.length, intMethodRefs.length);
for (int i = 0; i < allMethodRefs.length; i++)
{
String className = toClassName(new String(allMethodRefs[i].getClassName()));
char[][] paramChars = Signature.getParameterTypes(allMethodRefs[i].getMethodDescriptor());
String[] params = new String[paramChars.length];
for (int j = 0; j < params.length; j++)
params[j] = descriptor2Signature(paramChars[j]);
String returnType = descriptor2Signature(Signature.getReturnType(allMethodRefs[i].getMethodDescriptor()));
String methodName = new String(allMethodRefs[i].getMethodName());
ClassApi classApi = addUniqueClassApi(sourceClass, className, true, false, false, false);
MethodApi methodApi = newMethodApi(methodName, params, returnType);
classApi.getMethodApi().add(methodApi);
}
// field references
IConstantPoolEntry[] fieldRefs = type.getConstantPoolEntries(IConstantPoolConstant.CONSTANT_Fieldref);
for (int i = 0; i < fieldRefs.length; i++)
{
String className = toClassName(new String(fieldRefs[i].getClassName()));
String fieldType = descriptor2Signature(fieldRefs[i].getFieldDescriptor());
String fieldName = new String(fieldRefs[i].getFieldName());
ClassApi classApi = addUniqueClassApi(sourceClass, className, true, false, false, false);
FieldApi fieldApi = newFieldApi(fieldName, fieldType);
classApi.getFieldApi().add(fieldApi);
}
// use: reference
Set refTypes = type.getReferencedTypes();
for (Iterator refTypesIt = refTypes.iterator(); refTypesIt.hasNext();)
addUniqueClassApi(sourceClass, (String)refTypesIt.next(), true, false, false, false);
// use: subclass
if (!type.isInterface())
{
String superClass = type.getSuperClass();
if (superClass != null)
addUniqueClassApi(sourceClass, superClass, false, true, false, false);
}
// use: implement
String[] interfaces = type.getInterfaces();
for (int i = 0; i < interfaces.length; i++)
addUniqueClassApi(sourceClass, interfaces[i], false, false, true, false);
// use: instantiate
}
}
}
}
saveComponentUse(compUse, new File(comp.getCompLoc() + Component.CONST_COMPONENT_USE_XML));
comp.setCompUseXML(compUse);
}
}
private ClassApi addClassApi(ComponentType comp, Type type, ComponentApiType compApi)
{
String typeName = type.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;
}
boolean isInterface = type.isInterface();
PackageType pkgType = findPackageType(comp, pkgName);
if (pkgType != null)
{
TypeType typeType = findTypeType(pkgType, localName);
if (typeType != null)
{
boolean ref = typeType.isReference();
boolean subclass = typeType.isSubclass() && !isInterface;
boolean implement = typeType.isImplement() && isInterface;
boolean instantiate = typeType.isInstantiate() && !isInterface;
if (ref || subclass || implement || instantiate)
{
// at least one public usage
ClassApi classApi = newClassApi(typeName, ref, subclass, implement, instantiate);
addClassApi(compApi, false, pkgName, classApi);
return classApi;
}
else
{
// all usage are set to false, in another word, it is an internal API
ClassApi classApi = newClassApi(typeName, true, !isInterface, isInterface, !isInterface);
addClassApi(compApi, true, pkgName, classApi);
return classApi;
}
}
else if (pkgType.isApi())
{
// api == true means, by default, a non-listed type is an external API
ClassApi classApi = newClassApi(typeName, true, !isInterface, isInterface, !isInterface);
addClassApi(compApi, false, pkgName, classApi);
return classApi;
}
else
{
// api == false means, by default, a non-listed type is an internal API
ClassApi classApi = newClassApi(typeName, true, !isInterface, isInterface, !isInterface);
addClassApi(compApi, true, pkgName, classApi);
return classApi;
}
}
else
{
// package not defined in component.xml means it is an internal API
ClassApi classApi = newClassApi(typeName, true, !isInterface, isInterface, !isInterface);
addClassApi(compApi, true, pkgName, classApi);
return classApi;
}
}
private void addClassApi(ComponentApiType comp, boolean isInternal, String pkgName, ClassApi classApi)
{
ApiTypes apis = (isInternal) ? comp.getInternalApis() : comp.getExternalApis();
EList pkgs = apis.getPackage();
Package pkg = null;
for (Iterator it = pkgs.iterator(); it.hasNext();)
{
Package nextPkg = (Package)it.next();
if (nextPkg.getName().equals(pkgName))
{
pkg = nextPkg;
break;
}
}
if (pkg == null)
{
pkg = newPackage(pkgName);
pkgs.add(pkg);
}
pkg.getClassApi().add(classApi);
}
private void addMethodApi(ClassApi classApi, MethodApi methodApi)
{
classApi.getMethodApi().add(methodApi);
}
private void addFieldApi(ClassApi classApi, FieldApi fieldApi)
{
classApi.getFieldApi().add(fieldApi);
}
private void addSourceClass(ComponentUseType compUse, SourceClass sourceClass)
{
compUse.getSourceClass().add(sourceClass);
}
private ClassApi addUniqueClassApi(SourceClass sourceClass, String className, boolean ref, boolean subclass, boolean implement, boolean instantiate)
{
EList classApis = sourceClass.getClassUse();
for (Iterator it = classApis.iterator(); it.hasNext();)
{
ClassApi classApi = (ClassApi)it.next();
if (classApi.getName().equals(className) && classApi.isReference() == ref && classApi.isSubclass() == subclass && classApi.isImplement() == implement && classApi.isInstantiate() == instantiate)
return classApi;
}
ClassApi classApi = newClassApi(className, ref, subclass, implement, instantiate);
classApis.add(classApi);
return classApi;
}
private ComponentApiType newComponentApiType()
{
ComponentApiType comp = ApiFactory.eINSTANCE.createComponentApiType();
ApiTypes internalApis = ApiFactory.eINSTANCE.createApiTypes();
ApiTypes externalApis = ApiFactory.eINSTANCE.createApiTypes();
comp.setInternalApis(internalApis);
comp.setExternalApis(externalApis);
return comp;
}
private Package newPackage(String pkgName)
{
Package pkg = ApiFactory.eINSTANCE.createPackage();
pkg.setName(pkgName);
return pkg;
}
private ClassApi newClassApi(String typeName, boolean ref, boolean subclass, boolean implement, boolean instantiate)
{
ClassApi classApi = ApiFactory.eINSTANCE.createClassApi();
classApi.setName(typeName);
classApi.setReference(ref);
classApi.setSubclass(subclass);
classApi.setImplement(implement);
classApi.setInstantiate(instantiate);
return classApi;
}
private MethodApi newMethodApi(String methodName, boolean isPublic, boolean isStatic, boolean isFinal, boolean isSynchronized, boolean isNative, boolean isAbstract, boolean isStrict, String[] params, String returnType, String[] exceptions)
{
MethodApi methodApi = ApiFactory.eINSTANCE.createMethodApi();
methodApi.setName(methodName);
if (isPublic)
methodApi.setVisibility(Visibility.PUBLIC_LITERAL);
else
methodApi.setVisibility(Visibility.PROTECTED_LITERAL);
methodApi.setStatic(isStatic);
methodApi.setFinal(isFinal);
methodApi.setSynchronized(isSynchronized);
methodApi.setNative(isNative);
methodApi.setAbstract(isAbstract);
methodApi.setStrict(isStrict);
List inputType = new Vector();
for (int i = 0; i < params.length; i++)
inputType.add(params[i]);
methodApi.setInputType(inputType);
methodApi.setReturnType(returnType);
List exList = new Vector();
for (int i = 0; i < exceptions.length; i++)
exList.add(exceptions[i]);
methodApi.setExceptionType(exList);
return methodApi;
}
private MethodApi newMethodApi(String methodName, String[] params, String returnType)
{
MethodApi methodApi = ApiFactory.eINSTANCE.createMethodApi();
methodApi.setName(methodName);
List inputType = new Vector();
for (int i = 0; i < params.length; i++)
inputType.add(params[i]);
methodApi.setInputType(inputType);
methodApi.setReturnType(returnType);
return methodApi;
}
private FieldApi newFieldApi(String fieldName, boolean isPublic, boolean isStatic, boolean isFinal, boolean isVolatile, boolean isTransient, String type)
{
FieldApi fieldApi = ApiFactory.eINSTANCE.createFieldApi();
fieldApi.setName(fieldName);
if (isPublic)
fieldApi.setVisibility(Visibility.PUBLIC_LITERAL);
else
fieldApi.setVisibility(Visibility.PROTECTED_LITERAL);
fieldApi.setStatic(isStatic);
fieldApi.setFinal(isFinal);
fieldApi.setVolatile(isVolatile);
fieldApi.setTransient(isTransient);
fieldApi.setType(type);
return fieldApi;
}
private FieldApi newFieldApi(String fieldName, String type)
{
FieldApi fieldApi = ApiFactory.eINSTANCE.createFieldApi();
fieldApi.setName(fieldName);
fieldApi.setType(type);
return fieldApi;
}
private ComponentUseType newComponentUseType()
{
ComponentUseType compUse = UseFactory.eINSTANCE.createComponentUseType();
return compUse;
}
private SourceClass newSourceClass(String className)
{
SourceClass source = UseFactory.eINSTANCE.createSourceClass();
source.setName(className);
return source;
}
private PackageType findPackageType(ComponentType comp, String pkgName)
{
if (pkgName != null)
{
EList pkgs = comp.getPackage();
for (Iterator it = pkgs.iterator(); it.hasNext();)
{
PackageType pkg = (PackageType)it.next();
if (pkgName.equals(pkg.getName()))
return pkg;
}
}
return null;
}
private TypeType findTypeType(PackageType pkg, String typeName)
{
if (typeName != null)
{
EList types = pkg.getType();
for (Iterator it = types.iterator(); it.hasNext();)
{
TypeType type = (TypeType)it.next();
if (typeName.equals(type.getName()))
return type;
}
}
return null;
}
private boolean isBit (int flag, int bit)
{
return ((flag & bit) == bit);
}
private String descriptor2Signature(char[] descriptor)
{
return toClassName(Signature.toString(new String(descriptor)));
}
private String toClassName(String className)
{
return className.replace('/', '.');
}
private void saveComponentApi(ComponentApiType componentApi, File file) throws IOException
{
ResourceSet res = new ResourceSetImpl();
res.getResourceFactoryRegistry().getExtensionToFactoryMap().put("componentapi", new ApiResourceFactoryImpl());
res.getPackageRegistry().put(ApiPackage.eNS_URI, ApiPackage.eINSTANCE);
ApiResourceImpl apiRes = (ApiResourceImpl)res.createResource(URI.createURI("*.componentapi"));
org.eclipse.component.api.DocumentRoot root = ApiFactory.eINSTANCE.createDocumentRoot();
root.setComponentApi(componentApi);
apiRes.getContents().add(root);
apiRes.save(new BufferedOutputStream(new FileOutputStream(file)), new HashMap());
}
private void saveComponentUse(ComponentUseType componentUse, File file) throws IOException
{
ResourceSet res = new ResourceSetImpl();
res.getResourceFactoryRegistry().getExtensionToFactoryMap().put("componentuse", new UseResourceFactoryImpl());
res.getPackageRegistry().put(UsePackage.eNS_URI, UsePackage.eINSTANCE);
UseResourceImpl useRes = (UseResourceImpl)res.createResource(URI.createURI("*.componentuse"));
org.eclipse.component.use.DocumentRoot root = UseFactory.eINSTANCE.createDocumentRoot();
root.setComponentUse(componentUse);
useRes.getContents().add(root);
useRes.save(new BufferedOutputStream(new FileOutputStream(file)), new HashMap());
}
public Map getComponents()
{
return compName2Comp;
}
}