blob: 7590663ce393697b4cd182893133c5597b3615c0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 NumberFour AG
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* NumberFour AG - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.javascript.typeinfo;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
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.eclipse.dltk.javascript.core.JavaScriptPlugin;
import org.osgi.framework.Bundle;
/**
* Helper class for contributing {@link MetaType} implementations from enums.
*/
public class MetaTypeFactory implements IExecutableExtensionFactory,
IExecutableExtension {
private IConfigurationElement config;
private String className;
public void setInitializationData(IConfigurationElement config,
String propertyName, Object data) throws CoreException {
if (data instanceof String)
className = (String) data;
else
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0,
"Data argument must be a String for " + getClass(), null));
this.config = config;
}
public Object create() throws CoreException {
if (className == null) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0,
"Class name not specified for " + getClass(), null));
}
final int dot = className.lastIndexOf('.');
if (dot == -1) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "Illegal class name "
+ className + " for " + getClass(), null));
}
final String bundleName = config.getContributor().getName();
final Bundle bundle = Platform.getBundle(bundleName);
if (bundle == null) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "Bundle " + bundleName
+ " not found for " + getClass(), null));
}
try {
final Class<?> clazz = bundle
.loadClass(className.substring(0, dot));
final String name = className.substring(dot + 1);
if (!clazz.isEnum()) {
final Field field = clazz.getDeclaredField(name);
if (isConstField(field)) {
try {
return field.get(null);
} catch (IllegalAccessException e) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "Error reading "
+ field, e));
}
} else {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "Field " + field
+ " must be public static final", null));
}
}
final Enum<?>[] entries = (Enum<?>[]) clazz.getEnumConstants();
for (Enum<?> entry : entries) {
if (name.equals(entry.name())) {
return entry;
}
}
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "No enum const " + className
+ " for " + getClass(), null));
} catch (ClassNotFoundException e) {
// fall-through and try the whole string
} catch (NoSuchFieldException e1) {
// fall-through and try the whole string
}
try {
final Class<?> clazz = bundle.loadClass(className);
if (!clazz.isEnum()) {
final List<Field> fields = new ArrayList<Field>();
for (Field field : clazz.getDeclaredFields()) {
if (isConstField(field)) {
fields.add(field);
}
}
if (fields.size() != 1) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0,
"Single public static final field expected in "
+ clazz.getName() + " for " + getClass(),
null));
}
try {
return fields.get(0).get(null);
} catch (IllegalAccessException e) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "Error reading "
+ fields.get(0), e));
}
}
final Object[] entries = clazz.getEnumConstants();
if (entries.length != 1) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0,
"Single enum const expected in " + clazz.getName()
+ " for " + getClass(), null));
}
return entries[0];
} catch (ClassNotFoundException e) {
throw new CoreException(new Status(IStatus.ERROR,
JavaScriptPlugin.PLUGIN_ID, 0, "Class " + className
+ " not found for " + getClass(), e));
}
}
private boolean isConstField(Field field) {
return (field.getModifiers() & (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL)) == (Modifier.PUBLIC
| Modifier.STATIC | Modifier.FINAL);
}
}