blob: 7c589e5fc579e4bdfeffad38976a29507314752c [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 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.ui.internal.adopter.action;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.core.util.IClassFileReader;
import org.eclipse.jdt.core.util.IFieldInfo;
import org.eclipse.jdt.core.util.IMethodInfo;
import org.eclipse.jdt.internal.core.util.ClassFileReader;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wtp.releng.tools.component.adopters.BreakageReport;
import org.eclipse.wtp.releng.tools.component.adopters.ClassRef;
import org.eclipse.wtp.releng.tools.component.adopters.FieldRef;
import org.eclipse.wtp.releng.tools.component.adopters.MethodRef;
import org.eclipse.wtp.releng.tools.component.adopters.PluginRef;
import org.eclipse.wtp.releng.tools.component.adopters.References;
import org.eclipse.wtp.releng.tools.component.api.ClassAPI;
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.ui.Message;
import org.eclipse.wtp.releng.tools.component.ui.internal.ComponentUIPlugin;
import org.eclipse.wtp.releng.tools.component.ui.internal.adopter.preference.UsageReportsPrefPage;
import org.eclipse.wtp.releng.tools.component.ui.internal.adopter.view.BreakageReportView;
public class Scan4APIRefCompatibility extends Action implements IActionDelegate
{
public void run()
{
List refs = UsageReportsPrefPage.getReferences();
IContainer output = UsageReportsPrefPage.getOutput();
if (refs.isEmpty())
{
MessageDialog.openError(Display.getDefault().getActiveShell(), Message.getMessage("TITLE_USAGE_REPORTS_NOT_FOUND"), Message.getMessage("MSG_ERROR_PLEASE_ADD_USAGE_REPORTS"));
return;
}
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null)
{
IStructuredSelection selections = (IStructuredSelection)window.getSelectionService().getSelection();
for (Iterator it = selections.iterator(); it.hasNext();)
{
try
{
IProject project = (IProject)it.next();
IJavaProject javaProject = JavaCore.create(project);
IPath outputLoc = javaProject.getOutputLocation();
IFolder bin = (IFolder)ResourcesPlugin.getWorkspace().getRoot().findMember(outputLoc);
final Map classAPIs = new HashMap();
bin.accept(new IResourceProxyVisitor()
{
public boolean visit(IResourceProxy proxy) throws CoreException
{
if (proxy.getName().endsWith(".class"))
{
try
{
IClassFileReader reader = read((IFile)proxy.requestResource());
ClassAPI classAPI = new ClassAPI();
String className = new String(reader.getClassName()).replace('/', '.');
classAPI.setName(className);
classAPI.setAccess(reader.getAccessFlags());
classAPI.setSuperClass(new String(reader.getSuperclassName()).replace('/', '.'));
char[][] interfaces = reader.getInterfaceNames();
for (int i = 0; i < interfaces.length; i++)
{
classAPI.addInterface(new String(interfaces[i]).replace('/', '.'));
}
classAPIs.put(className, classAPI);
IMethodInfo[] methods = reader.getMethodInfos();
for (int i = 0; i < methods.length; i++)
{
MethodAPI methodAPI = new MethodAPI();
methodAPI.setName(new String(methods[i].getName()));
methodAPI.setDescriptor(new String(methods[i].getDescriptor()));
classAPI.addMethodAPI(methodAPI);
}
IFieldInfo[] fields = reader.getFieldInfos();
for (int i = 0; i < fields.length; i++)
{
FieldAPI fieldAPI = new FieldAPI();
fieldAPI.setName(new String(fields[i].getName()));
classAPI.addFieldAPI(fieldAPI);
}
}
catch (Throwable t)
{
t.printStackTrace();
}
}
return true;
}
}, IContainer.NONE);
String pluginId = project.getName();
BreakageReport breakageReport = new BreakageReport();
for (Iterator it4 = refs.iterator(); it4.hasNext();)
{
boolean isCompatible = true;
References ref = (References)it4.next();
References brokenRefs = new References();
brokenRefs.setName(ref.getName());
brokenRefs.setContactInfo(ref.getContactInfo());
brokenRefs.setRefBuildId(ref.getRefBuildId());
PluginRef pluginRef = ref.getPluginRef(pluginId);
if (pluginRef != null)
{
PluginRef brokenPluginRef = new PluginRef();
brokenPluginRef.setId(pluginId);
brokenRefs.addPluginRef(brokenPluginRef);
for (Iterator it2 = pluginRef.getClassRefs().iterator(); it2.hasNext();)
{
ClassRef classRef = (ClassRef)it2.next();
String className = classRef.getName();
if (className.endsWith("[]"))
className = className.substring(0, className.length() - 2);
ClassAPI classAPI = (ClassAPI)classAPIs.get(className);
if (classAPI == null)
{
brokenPluginRef.addClassRef(classRef);
isCompatible = false;
}
else
{
for (Iterator it3 = classRef.getMethodRefs().iterator(); it3.hasNext();)
{
MethodRef methodRef = (MethodRef)it3.next();
String methodName = methodRef.getName();
String methodDescriptor = methodRef.getDescriptor();
if (!methodExists(classAPIs, className, methodName, methodDescriptor, javaProject))
{
ClassRef brokenClassRef = brokenPluginRef.getClassRef(className);
if (brokenClassRef == null)
{
brokenClassRef = new ClassRef();
brokenClassRef.setName(className);
brokenPluginRef.addClassRef(brokenClassRef);
}
brokenClassRef.addMethodRef(methodRef);
isCompatible = false;
}
}
for (Iterator it3 = classRef.getFieldRefs().iterator(); it3.hasNext();)
{
FieldRef fieldRef = (FieldRef)it3.next();
String fieldName = fieldRef.getName();
if (!fieldExists(classAPIs, className, fieldName, javaProject))
{
ClassRef brokenClassRef = brokenPluginRef.getClassRef(className);
if (brokenClassRef == null)
{
brokenClassRef = new ClassRef();
brokenClassRef.setName(className);
brokenPluginRef.addClassRef(brokenClassRef);
}
brokenClassRef.addFieldRef(fieldRef);
isCompatible = false;
}
}
}
}
}
if (!isCompatible)
{
breakageReport.addRefs(brokenRefs);
}
}
BreakageReportView view = (BreakageReportView)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("org.eclipse.wtp.releng.tools.component.ui.internal.adopter.view.BreakageReportView");
StringBuffer sb = new StringBuffer();
sb.append(pluginId);
sb.append(".breakage");
IFile file = output.getFile(new Path(sb.toString()));
if (breakageReport.getRefs().isEmpty())
{
if (file.exists())
{
file.delete(true, false, new NullProgressMonitor());
}
view.clear();
MessageDialog.openInformation(Display.getDefault().getActiveShell(), Message.getMessage("TITLE_COMPATIBLE_WITH_USAGE_REPORTS"), Message.getMessage("MSG_INFO_COMPATIBLE_WITH_USAGE_REPORTS"));
}
else
{
ByteArrayInputStream bais = new ByteArrayInputStream(breakageReport.toString().getBytes());
if (file.exists())
{
file.setContents(bais, true, false, new NullProgressMonitor());
}
else
{
file.create(bais, true, new NullProgressMonitor());
}
view.setFocus();
view.refresh();
}
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}
}
private IClassFileReader read(IFile file) throws IOException, ClassFormatException, CoreException
{
InputStream is = null;
ByteArrayOutputStream baos = null;
try
{
byte[] b = new byte[8192];
baos = new ByteArrayOutputStream(8192);
is = file.getContents();
for (int read = is.read(b); read != -1; read = is.read(b))
{
baos.write(b, 0, read);
}
is.close();
baos.close();
return new ClassFileReader(baos.toByteArray(), IClassFileReader.CONSTANT_POOL | IClassFileReader.METHOD_INFOS | IClassFileReader.METHOD_BODIES | IClassFileReader.FIELD_INFOS | IClassFileReader.SUPER_INTERFACES);
}
finally
{
if (is != null)
{
try
{
is.close();
}
catch (IOException e)
{
}
}
if (baos != null)
{
try
{
baos.close();
}
catch (IOException e)
{
}
}
}
}
private boolean methodExists(Map classAPIs, String className, String methodName, String methodDescriptor, IJavaProject javaProject)
{
ClassAPI classAPI = (ClassAPI)classAPIs.get(className);
if (classAPI != null)
{
if (classAPI.getMethodAPI(methodName, methodDescriptor) != null)
{
return true;
}
else
{
String superClassName = classAPI.getSuperClass();
boolean exists = methodExists(classAPIs, superClassName, methodName, methodDescriptor, javaProject);
if (exists)
{
return true;
}
for (Iterator it = classAPI.getInterfaces().iterator(); it.hasNext();)
{
String superInterfaceName = (String)it.next();
exists = methodExists(classAPIs, superInterfaceName, methodName, methodDescriptor, javaProject);
if (exists)
{
return true;
}
}
return false;
}
}
else
{
try
{
IType type = getType(javaProject, className);
return methodExists(javaProject, type, methodName, toParameterTypes(methodDescriptor));
}
catch (Throwable t)
{
t.printStackTrace();
return false;
}
}
}
private boolean fieldExists(Map classAPIs, String className, String fieldName, IJavaProject javaProject)
{
ClassAPI classAPI = (ClassAPI)classAPIs.get(className);
if (classAPI != null)
{
if (classAPI.getFieldAPI(fieldName) != null)
{
return true;
}
else
{
String superClassName = classAPI.getSuperClass();
boolean exists = fieldExists(classAPIs, superClassName, fieldName, javaProject);
if (exists)
{
return true;
}
for (Iterator it = classAPI.getInterfaces().iterator(); it.hasNext();)
{
String superInterfaceName = (String)it.next();
exists = fieldExists(classAPIs, superInterfaceName, fieldName, javaProject);
if (exists)
{
return true;
}
}
return false;
}
}
else
{
try
{
IType type = getType(javaProject, className);
return fieldExists(javaProject, type, fieldName);
}
catch (Throwable t)
{
t.printStackTrace();
return false;
}
}
}
private SearchEngine se = new SearchEngine();
private IType getType(IJavaProject javaProject, String className) throws CoreException
{
StringTokenizer innerClassTokens = null;
if (className.indexOf('$') != -1)
{
innerClassTokens = new StringTokenizer(className, "$");
className = innerClassTokens.nextToken();
}
SearchPattern spattern = SearchPattern.createPattern(className, IJavaSearchConstants.CLASS_AND_INTERFACE, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH);
SearchParticipant[] sparticipant = new SearchParticipant[]{SearchEngine.getDefaultSearchParticipant()};
IJavaSearchScope ijss = SearchEngine.createJavaSearchScope(new IJavaElement[]{javaProject});
ClassSearchRequestor csr = new ClassSearchRequestor();
se.search(spattern, sparticipant, ijss, csr, new NullProgressMonitor());
IType type = csr.getType();
if (type == null)
return null;
if (innerClassTokens == null)
return type;
else
{
while (innerClassTokens.hasMoreTokens())
{
type = type.getType(innerClassTokens.nextToken());
if (type == null)
return null;
}
return type;
}
}
private String[] toParameterTypes(String desc)
{
String[] paramTypes = Signature.getParameterTypes(desc);
for (int i = 0; i < paramTypes.length; i++)
{
paramTypes[i] = paramTypes[i].replace('/', '.');
}
return paramTypes;
}
private boolean methodExists(IJavaProject javaProject, IType type, String name, String[] paramTypes) throws JavaModelException, CoreException
{
if (type != null)
{
IMethod method = type.getMethod(name, paramTypes);
if (method.exists())
return true;
if (type.isClass())
{
String superClassName = type.getSuperclassName();
if (superClassName != null)
{
IType superType = getType(javaProject, superClassName);
return methodExists(javaProject, superType, name, paramTypes);
}
}
else
{
String[] interfaceNames = type.getSuperInterfaceNames();
for (int i = 0; i < interfaceNames.length; i++)
{
if (methodExists(javaProject, getType(javaProject, interfaceNames[i]), name, paramTypes))
{
return true;
}
}
}
}
return false;
}
private boolean fieldExists(IJavaProject javaProject, IType type, String name) throws JavaModelException, CoreException
{
if (type != null)
{
IField field = type.getField(name);
if (field.exists())
return true;
if (type.isClass())
{
String superClassName = type.getSuperclassName();
if (superClassName != null)
{
IType superType = getType(javaProject, superClassName);
return fieldExists(javaProject, superType, name);
}
}
else
{
String[] interfaceNames = type.getSuperInterfaceNames();
for (int i = 0; i < interfaceNames.length; i++)
{
if (fieldExists(javaProject, getType(javaProject, interfaceNames[i]), name))
{
return true;
}
}
}
}
return false;
}
public void run(IAction action)
{
run();
}
public void selectionChanged(IAction action, ISelection selection)
{
}
private class ClassSearchRequestor extends SearchRequestor
{
private IType type;
public IType getType()
{
return type;
}
public void acceptSearchMatch(SearchMatch match)
{
Object element = match.getElement();
if (element instanceof IType)
{
type = (IType)element;
}
}
}
}