package org.erlide.engine;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import javax.inject.Inject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IExecutableExtensionFactory;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.erlide.engine.services.ErlangService;
import org.osgi.framework.Bundle;
/**
* Use together with declared handlers like for example
*
* <pre>
* <code>
* <extension point="org.eclipse.ui.handlers">
* <handler
* class="org.erlide.core.ExecutableExtensionFactory:org.erlide.ui.my.MyHandler"
* commandId="org.erlide.ui.mycommand">
* </handler>
* </extension>
* </code>
* </pre>
*/
public class ExecutableExtensionsFactory
implements IExecutableExtensionFactory, IExecutableExtension {
private String className;
private Bundle bundle;
public ExecutableExtensionsFactory() {
}
@Override
public void setInitializationData(final IConfigurationElement config,
final String propertyName, final Object data) throws CoreException {
if (data instanceof String) {
className = (String) data;
}
final String contributor = config.getDeclaringExtension().getContributor()
.getName();
bundle = Platform.getBundle(contributor);
}
@Override
public Object create() throws CoreException {
final String bundleName = bundle.getSymbolicName();
try {
final Class<?> clazz = bundle.loadClass(className);
final Constructor<?> constructor = getDefaultConstructor(clazz);
final Class<?>[] parameterTypes = constructor.getParameterTypes();
final Object[] initargs = new Object[parameterTypes.length];
assignParameters(parameterTypes, initargs);
return constructor.newInstance(initargs);
} catch (final ClassNotFoundException e) {
throw new CoreException(new Status(IStatus.ERROR, bundleName,
"Could not load class " + className));
} catch (final InjectionException e) {
throw new CoreException(new Status(IStatus.ERROR, bundleName,
"Injection error for class " + className, e));
} catch (final IllegalArgumentException e) {
throw new CoreException(new Status(IStatus.ERROR, bundleName,
"Injection error for class " + className, e));
} catch (final InstantiationException e) {
throw new CoreException(new Status(IStatus.ERROR, bundleName,
"Injection error for class " + className, e));
} catch (final IllegalAccessException e) {
throw new CoreException(new Status(IStatus.ERROR, bundleName,
"Injection error for class " + className, e));
} catch (final InvocationTargetException e) {
throw new CoreException(new Status(IStatus.ERROR, bundleName,
"Injection error for class " + className, e));
}
}
private void assignParameters(final Class<?>[] parameterTypes,
final Object[] initargs) {
for (int i = 0; i < parameterTypes.length; i++) {
final Class<?> paramType = parameterTypes[i];
if (ErlangService.class.isAssignableFrom(paramType)) {
@SuppressWarnings("unchecked")
final Class<? extends ErlangService> serviceClass = (Class<? extends ErlangService>) paramType;
initargs[i] = injectParameter(serviceClass);
} else {
throw new InjectionException(
"Constructor parameters are not injectable (ErlangService)");
}
}
}
private Object injectParameter(final Class<? extends ErlangService> serviceClass) {
final Object parameter = ErlangEngine.getInstance().getService(serviceClass);
if (parameter != null) {
return parameter;
}
throw new InjectionException("Constructor parameter " + serviceClass.getName()
+ " could not be instantiated");
}
private Constructor<?> getDefaultConstructor(final Class<?> clazz) {
final Constructor<?>[] constructorArgs = clazz.getConstructors();
if (constructorArgs.length == 1) {
return constructorArgs[0];
}
for (final Constructor<?> constructor : constructorArgs) {
if (constructor.isAnnotationPresent(Inject.class)) {
return constructor;
}
}
throw new InjectionException("Could not find injectable constructor");
}
}