| /******************************************************************************* |
| * 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; |
| } |
| |
| } |