blob: 26eb337d2f1588ae10c6d56e38e756bfdacdec46 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Christian Pontesegger and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
package org.eclipse.ease.modules;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.ease.Activator;
import org.eclipse.ease.Logger;
import org.eclipse.ease.service.IScriptService;
import org.eclipse.ease.service.ScriptService;
import org.eclipse.ease.tools.ContributionTools;
import org.eclipse.jface.resource.ImageDescriptor;
import org.osgi.framework.Bundle;
import org.osgi.service.prefs.Preferences;
public class ModuleDefinition {
public static ModuleDefinition forInstance(Object element) {
final List<ModuleDefinition> modules = new ArrayList<>(ScriptService.getInstance().getAvailableModules());
return modules.stream().filter(d -> Objects.equals(d.getModuleClass(), element.getClass())).findAny().orElse(null);
}
public static class ModuleDependency {
/** Module dependency parameter name. */
private static final String CONFIG_DEPENDENCY_ID = "module";
private final IConfigurationElement fElement;
public ModuleDependency(IConfigurationElement element) {
fElement = element;
}
public String getId() {
return fElement.getAttribute(CONFIG_DEPENDENCY_ID);
}
public ModuleDefinition getDefinition() {
final IScriptService scriptService = ScriptService.getInstance();
return scriptService.getModuleDefinition(getId());
}
}
/** Module name parameter. */
private static final String NAME = "name";
/** Module class parameter. */
private static final String CLASS = "class";
/** Module visibility parameter. */
private static final String VISIBLE = "visible";
/** Module category parameter. */
private static final String CATEGORY = "category";
/** Module dependency node. */
private static final String DEPENDENCY = "dependency";
/** Module id parameter name. */
private static final String ID = "id";
/** Module icon parameter name. */
private static final String ICON = "icon";
/**
* Retrieve the module definition for a given module instance.
*
* @param module
* module instance to look up
* @return module definition or <code>null</code>
*/
public static ModuleDefinition getDefinition(final Object module) {
final IScriptService scriptService = ScriptService.getService();
for (final ModuleDefinition definition : scriptService.getAvailableModules()) {
if (definition.getModuleClass().equals(module.getClass()))
return definition;
}
return null;
}
/** Main configuration element for module. */
private final IConfigurationElement fConfig;
private IPath fPath = null;
public ModuleDefinition(final IConfigurationElement config) {
fConfig = config;
}
public String getName() {
return fConfig.getAttribute(NAME);
}
/**
* Get module dependencies.
*
* @return required dependencies
*/
public List<ModuleDependency> getDependencies() {
final List<ModuleDependency> dependencies = new ArrayList<>();
for (final IConfigurationElement element : fConfig.getChildren(DEPENDENCY))
dependencies.add(new ModuleDependency(element));
return dependencies;
}
/**
* Get the class definition of the provided module. Will not (by default) create an instance of this class, but look up the class definition directly.
*
* @return class definition of module contribution
*/
public Class<?> getModuleClass() {
final Bundle bundle = Platform.getBundle(fConfig.getDeclaringExtension().getContributor().getName());
if (bundle != null) {
try {
final String className = fConfig.getAttribute(CLASS);
return Platform.getBundle(fConfig.getDeclaringExtension().getContributor().getName()).loadClass(className);
} catch (final InvalidRegistryObjectException e) {
// ignore
} catch (final ClassNotFoundException e) {
// ignore
}
}
// we could not locate the class, try to create instance
final Object instance = createModuleInstance();
if (instance != null)
return createModuleInstance().getClass();
return null;
}
/**
* Create a new instance of the module.
*
* @return module instance
*/
public Object createModuleInstance() {
try {
return fConfig.createExecutableExtension(CLASS);
} catch (final CoreException e) {
// could not create class, ignore
Logger.error(Activator.PLUGIN_ID, "Could not create module instance", e);
}
return null;
}
/**
* Get visibility status of module. Modules have a default visibility stored in its definition. Users may override this setting using preferences. Invisible
* modules may still be used in scripts. However they are not visible in the UI.
*
* @return <code>true</code> when visible
*/
public boolean isVisible() {
final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID);
final Preferences node = prefs.node("modules");
return node.getBoolean(getPath().toString(), Boolean.parseBoolean(fConfig.getAttribute(VISIBLE)));
}
/**
* Sets visibility status of module in preferences
*
* @param visible
* <code>true</code> to make visible
*/
public void setVisible(final boolean visible) {
final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID);
final Preferences node = prefs.node("modules");
node.putBoolean(getPath().toString(), visible);
}
/**
* Reset visibility to defaults.
*/
public void resetVisible() {
final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(Activator.PLUGIN_ID);
final Preferences node = prefs.node("modules");
node.remove(getPath().toString());
}
/**
* Get the full module name. The full name consists of optional parent categories and the module name itself.
*
* @return absolute path of this module definition
*/
public IPath getPath() {
if (fPath == null) {
final IScriptService scriptService = ScriptService.getService();
fPath = new Path(getName());
String categoryID = fConfig.getAttribute(CATEGORY);
while (categoryID != null) {
final ModuleCategoryDefinition definition = scriptService.getAvailableModuleCategories().get(categoryID);
if (definition != null) {
fPath = new Path(definition.getName()).append(fPath);
categoryID = definition.getParentId();
} else {
// invalid category detected
Logger.error(Activator.PLUGIN_ID, "Invalid category \"" + categoryID + "\" detected for module \"" + getName() + "\"");
categoryID = null;
}
}
fPath = fPath.makeAbsolute();
}
return fPath;
}
public String getId() {
return (fConfig.getAttribute(ID) != null) ? fConfig.getAttribute(ID) : "";
}
public ImageDescriptor getImageDescriptor() {
return ContributionTools.getImageDescriptor(fConfig, ICON);
}
public String getBundleID() {
return fConfig.getContributor().getName();
}
public List<Method> getMethods() {
return ModuleHelper.getMethods(getModuleClass());
}
public List<Field> getFields() {
return ModuleHelper.getFields(getModuleClass());
}
/**
* Provide the help location for a given topic. Returns the help URI needed to open the according help page.
*
* @param topic
* help topic within module
* @return link to help
*/
public String getHelpLocation(final String topic) {
return "/" + getBundleID() + "/help/module_" + getId().replace(' ', '_').toLowerCase() + ".html" + ((topic != null) ? "#" + topic : "");
}
/**
* Check deprecation status of module.
*
* @return <code>true</code> when module is deprecated
*/
public boolean isDeprecated() {
return getModuleClass().getAnnotation(Deprecated.class) != null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((getId() == null) ? 0 : getId().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ModuleDefinition other = (ModuleDefinition) obj;
if (getId() == null) {
if (other.getId() != null)
return false;
} else if (!getId().equals(other.getId()))
return false;
return true;
}
}