blob: cd0fd256c6e7260abafc358442736cb5231fda65 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 Cisco Systems, Inc.
* 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:
* E. Dillon (Cisco Systems, Inc.) - reformat for Code Open-Sourcing
*******************************************************************************/
package org.eclipse.tigerstripe.workbench.internal.core.plugin.pluggable;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.velocity.VelocityContext;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.tigerstripe.workbench.TigerstripeException;
import org.eclipse.tigerstripe.workbench.generation.IRunConfig;
import org.eclipse.tigerstripe.workbench.internal.api.ITigerstripeRuntime;
import org.eclipse.tigerstripe.workbench.internal.api.plugins.PluginLogger;
import org.eclipse.tigerstripe.workbench.internal.core.plugin.PluginReport;
import org.eclipse.tigerstripe.workbench.internal.core.plugin.base.BasePlugin;
import org.eclipse.tigerstripe.workbench.internal.core.project.pluggable.M0ProjectDescriptor;
import org.eclipse.tigerstripe.workbench.internal.core.project.pluggable.PluggablePluginProject;
import org.eclipse.tigerstripe.workbench.plugins.EPluggablePluginNature;
import org.eclipse.tigerstripe.workbench.plugins.IPluginClasspathEntry;
import org.eclipse.tigerstripe.workbench.plugins.IPluginProperty;
import org.eclipse.tigerstripe.workbench.plugins.ITemplateBasedRule;
import org.eclipse.tigerstripe.workbench.plugins.IVelocityContextDefinition;
import org.eclipse.tigerstripe.workbench.plugins.LogLevel;
import org.eclipse.tigerstripe.workbench.project.IGeneratorDescriptor;
import org.eclipse.tigerstripe.workbench.project.IPluginConfig;
/**
* Housing for Pluggable plugin
*
* @author Eric Dillon
* @since 1.2
*/
public class PluggablePlugin extends BasePlugin {
public static final String TEMPLATE_PREFIX = "org/eclipse/tigerstripe/workbench/internal/core/plugin/pluggable/resources"; // $NON-NLS-1$
private static final String DEFAULT_LOG_DIR = "logs"; // $NON-NLS-1$
private static final String REPORTTEMPLATE = "PLUGGABLE_REPORT.vm"; // $NON-NLS-1$
private boolean canDelete = true;
protected URLClassLoader classLoader;
/**
* This is the path to a location where stuff is unzipped
*/
private String path;
protected IGeneratorDescriptor descriptor = null;
private String[] definedProperties = null;
private PluggablePluginReport report;
private ITigerstripeRuntime runtime;
public PluggablePlugin() {
}
/**
*
* @param path
* - The path to the unzipped plugin directory
* @throws TigerstripeException
*/
public PluggablePlugin(ITigerstripeRuntime runtime, String path) throws TigerstripeException {
this.runtime = runtime;
this.path = path;
loadProject();
}
public ITigerstripeRuntime getRuntime() {
return runtime;
}
public void setRuntime(ITigerstripeRuntime runtime) {
this.runtime = runtime;
}
public EPluggablePluginNature getPluginNature() {
return descriptor.getPluginNature();
}
public void dispose() {
if (descriptor != null) {
descriptor.dispose();
}
if (classLoader != null) {
try {
classLoader.close();
} catch (IOException e) {
runtime.logErrorMessage("Failed to close plugin classloader", e);
}
classLoader = null;
}
this.path = null;
this.runtime = null;
}
private void logClassPath(PluginLogger pluginLogger, ClassLoader loader) {
// Get the URLs
if (loader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) loader).getURLs();
for (int i = 0; i < urls.length; i++) {
pluginLogger.log(LogLevel.DEBUG, "Classpath entry : " + urls[i].getFile(), null);
}
if (loader.getParent() != null) {
logClassPath(pluginLogger, loader.getParent());
}
}
}
public void trigger(IPluginConfig pluginConfig, IRunConfig config, PluginLogger pluginLogger)
throws TigerstripeException {
this.report = new PluggablePluginReport(pluginConfig);
this.report.setTemplate(TEMPLATE_PREFIX + "/" + REPORTTEMPLATE);
// Update the pluginConfig with any missing properties, and
// remove any that are not valid.
if (isLogEnabled()) {
// Add the classpath entries to the plugin log
logClassPath(pluginLogger, getClassloader());
}
Properties properties = pluginConfig.getProperties();
String[] definedProps = pluginConfig.getDefinedProperties();
Properties usableProps = new Properties();
for (int i = 0; i < definedProps.length; i++) {
if (properties.getProperty(definedProps[i]) == null
|| properties.getProperty(definedProps[i]).length() == 0) {
for (IPluginProperty property : descriptor
.getGlobalProperties()) {
if (property.getName().equals(definedProps[i])) {
usableProps.setProperty(definedProps[i], property
.getDefaultValue().toString());
}
}
} else {
usableProps.setProperty(definedProps[i], properties
.getProperty(definedProps[i]));
}
}
pluginConfig.setProperties(usableProps);
PluginRuleExecutor executor = new PluginRuleExecutor(this,
(PluggablePluginConfig) pluginConfig, config, pluginLogger);
executor.trigger();
ArrayList<RuleReport> ruleReports = executor.getReports();
this.report.getChildReports().addAll(ruleReports);
}
public String getLabel() {
return getPluginId();
}
public String getDescription() {
try {
return descriptor.getProjectDetails().getDescription();
} catch (TigerstripeException e) {
return "No description";
}
}
public IGeneratorDescriptor getPProject() {
return descriptor;
}
public String getPluginId() {
return getPluginName();
}
public String getPluginName() {
// Think this is needed to handle a bug where the name is not set in the descriptor !!
String name;
try {
name = descriptor.getProjectDetails().getName();
} catch (TigerstripeException e) {
return "Failed to retrieve";
}
if ( name.length() == 0) {
name = descriptor.getProjectLabel();
if (name.contains("-"))
name = name.substring(1,name.indexOf('-'));
}
return name;
}
public String getGroupId() {
try {
return descriptor.getProjectDetails().getProvider();
} catch (TigerstripeException e) {
return "Failed to retrieve";
}
}
public String getVersion() {
try {
return descriptor.getProjectDetails().getVersion();
} catch (TigerstripeException e) {
return "Failed to retrieve";
}
}
public PluginReport getReport() {
return this.report;
}
public String[] getSupportedNatures() {
// TODO Auto-generated method stub
return null;
}
public String[] getDefinedProperties() {
if (definedProperties == null) {
ArrayList<String> result = new ArrayList<>();
IPluginProperty[] props = descriptor.getGlobalProperties();
for (IPluginProperty prop : props) {
result.add(prop.getName());
}
definedProperties = result.toArray(new String[result.size()]);
}
return definedProperties;
}
public int getCategory() {
// TODO Auto-generated method stub
return 0;
}
public boolean isValid() {
if (descriptor == null) {
try {
loadProject();
} catch (TigerstripeException e) {
return false;
}
}
return descriptor != null && descriptor.isValid();
}
protected void loadProject() throws TigerstripeException {
descriptor = new PluggablePluginProject(runtime, new File(path));
if (!descriptor.getFullPath().exists()) {
descriptor = new M0ProjectDescriptor(runtime, new File(path));
}
try {
descriptor.reload(true);
if (!descriptor.isValid()) {
descriptor = null;
}
} catch (TigerstripeException e) {
throw new TigerstripeException("Error creating Descriptor", e);
}
}
/**
* Builds the velocity context as defined in the project descriptor by
* creating a classloader that will include the .class files that have been
* packaged up.
*
* @param parentContext
* @return
* @throws TigerstripeException
*/
public VelocityContext getLocalVelocityContext(
VelocityContext parentContext, ITemplateBasedRule rule)
throws TigerstripeException {
VelocityContext result = new VelocityContext(parentContext);
IVelocityContextDefinition[] contextDefs = rule
.getVelocityContextDefinitions();
for (IVelocityContextDefinition def : contextDefs) {
Object entryObj = getInstance(def.getClassname());
result.put(def.getName(), entryObj);
}
return result;
}
/**
* Gets the corresponding class from the Plugin Classloader
*
* @param classname
* @return
* @throws TigerstripeException
*/
protected Class<?> getClass(String classname) throws TigerstripeException {
try {
Class<?> cl = getClassloader().loadClass(classname);
return cl;
} catch (ClassNotFoundException e) {
throw new TigerstripeException("Couldn't find class '" + classname
+ "' in plugin classloader ('" + getLabel() + "')");
}
}
public Object getInstance(String classname) throws TigerstripeException {
try {
Class<?> clazz = getClass(classname);
return clazz.newInstance();
} catch (InstantiationException e) {
throw new TigerstripeException("Couldn't instantiate class '"
+ classname + "' within context of plugin ('" + getLabel()
+ "'): " + e.getMessage(), e);
} catch (IllegalAccessException e) {
throw new TigerstripeException("Couldn't access class '"
+ classname + "' within context of plugin ('" + getLabel()
+ "'): " + e.getMessage(), e);
}
}
protected ClassLoader getClassloader() throws TigerstripeException {
try {
if (classLoader == null) {
List<URL> urls = new ArrayList<>();
// Create a classloader that includes the additional classpath
File classesDir = new File(getPProject().getBaseDir(),
"classes");
urls.add(classesDir.toURL());
// with all packaged up entries
for (IPluginClasspathEntry entry : getPProject()
.getClasspathEntries()) {
File jarFile = new File(getPProject().getBaseDir(), entry
.getRelativePath());
urls.add(jarFile.toURL());
}
classLoader = new URLClassLoader(urls.toArray(new URL[urls
.size()]), this.getClass().getClassLoader());
}
return classLoader;
} catch (MalformedURLException e) {
throw new TigerstripeException(
"Unable to create plugin classloader for '" + getLabel()
+ "':" + e.getMessage(), e);
}
}
@Override
public LogLevel getDefaultLogLevel() {
return descriptor.getDefaultLogLevel();
}
@Override
public String getLogPath() {
IPath logPath = new Path(DEFAULT_LOG_DIR);
return logPath.append(descriptor.getLogPath()).toOSString();
}
@Override
public boolean isLogEnabled() {
return descriptor.isLogEnabled();
}
public String getPluginPath() {
return path;
}
public void setCanDelete(boolean canDelete){
this.canDelete = canDelete;
}
public boolean getCanDelete() {
return canDelete;
}
}