package org.xpect.ui.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.jar.JarFile;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.xtext.common.types.JvmExecutable;
import org.eclipse.xtext.common.types.JvmField;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.access.IMirror;
import org.eclipse.xtext.common.types.access.TypeResource;
import org.eclipse.xtext.common.types.access.impl.ClassMirror;
import org.eclipse.xtext.common.types.access.jdt.JdtTypeMirror;
import org.eclipse.xtext.common.types.util.JavaReflectAccess;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.xpect.util.ClasspathUtil;
import org.xpect.util.IJavaReflectAccess;
import com.google.common.collect.Lists;
@SuppressWarnings("restriction")
public class UIJavaReflectAccess implements IJavaReflectAccess {
private final static Logger LOG = Logger.getLogger(UIJavaReflectAccess.class);
private Bundle getBundle(ClassMirror mirror) {
Class<?> mirroredClass = mirror.getMirroredClass();
return FrameworkUtil.getBundle(mirroredClass);
}
private Bundle getBundle(JdtTypeMirror mirror) {
IType mirroredType = mirror.getMirroredType();
IPackageFragmentRoot fragmentRoot = getPackageFragmentRoot(mirroredType);
if (fragmentRoot == null || fragmentRoot.getPath() == null)
return null;
File file = fragmentRoot.getPath().toFile();
String bundleName;
if (file.isFile())
bundleName = getBundleNameFromJar(file);
else if (file.isDirectory())
bundleName = getBundleNameFromDir(file);
else
return null;
if (bundleName == null)
return null;
return Platform.getBundle(bundleName);
}
private String getBundleNameFromDir(File file) {
File current = file;
int counter = 5;
while (current != null && counter > 0) {
File cand = new File(current + "/META-INF/MANIFEST.MF");
if (cand.isFile()) {
try {
return ClasspathUtil.getSymbolicName(new FileInputStream(cand));
} catch (FileNotFoundException e) {
LOG.error("Can't get symbolic name from " + cand, e);
return null;
}
}
current = current.getParentFile();
}
return null;
}
private String getBundleNameFromJar(File file) {
try {
return ClasspathUtil.getSymbolicName(new JarFile(file).getManifest());
} catch (IOException e) {
LOG.error("Can't get symbolic name from " + file, e);
return null;
}
}
public Field getField(JvmField field) {
Class<?> rawType = getRawType(field.getDeclaringType());
if (rawType == null)
return null;
try {
return rawType.getDeclaredField(field.getSimpleName());
} catch (Exception e) {
LOG.error("Can't find " + field.getIdentifier(), e);
return null;
}
}
public Method getMethod(JvmOperation operation) {
Class<?> rawType = getRawType(operation.getDeclaringType());
if (rawType == null)
return null;
Class<?>[] paramTypes = getParamTypes(operation);
try {
return rawType.getDeclaredMethod(operation.getSimpleName(), paramTypes);
} catch (Exception e) {
LOG.error("Can't find " + operation.getIdentifier(), e);
return null;
}
}
private IPackageFragmentRoot getPackageFragmentRoot(IJavaElement ele) {
IJavaElement current = ele;
while (current != null) {
if (current instanceof IPackageFragmentRoot)
return (IPackageFragmentRoot) current;
current = current.getParent();
}
return null;
}
private Class<?>[] getParamTypes(JvmExecutable exe) {
List<JvmFormalParameter> parameters = exe.getParameters();
List<Class<?>> result = Lists.newArrayList();
for (JvmFormalParameter p : parameters) {
result.add(getRawType(p.getParameterType().getType()));
}
return result.toArray(new Class<?>[result.size()]);
}
public Class<?> getRawType(JvmType jvmType) {
if (jvmType == null || jvmType.eIsProxy())
return null;
XtextResourceSet resourceSet = (XtextResourceSet) jvmType.eResource().getResourceSet();
if (resourceSet.getClasspathURIContext() instanceof ClassLoader) {
JavaReflectAccess access = new JavaReflectAccess();
access.setClassLoader((ClassLoader) resourceSet.getClasspathURIContext());
return access.getRawType(jvmType);
}
if (!(jvmType.eResource() instanceof TypeResource))
return null;
IMirror typeMirror = ((TypeResource) jvmType.eResource()).getMirror();
Bundle bundle = null;
if (typeMirror instanceof JdtTypeMirror)
bundle = getBundle((JdtTypeMirror) typeMirror);
if (typeMirror instanceof ClassMirror)
bundle = getBundle((ClassMirror) typeMirror);
if (bundle == null)
return null;
String className = jvmType.getQualifiedName();
try {
return bundle.loadClass(className);
} catch (ClassNotFoundException e) {
LOG.error("Could not find Java class for " + jvmType.eClass().getName() + " " + jvmType.getIdentifier(), e);
return null;
}
}
}