Java tutorial
/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2015 Pentaho Corporation. All rights reserved. */ package org.pentaho.marketplace.domain.services; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.karaf.features.Feature; import org.apache.karaf.features.FeaturesService; import org.apache.karaf.kar.KarService; import org.apache.commons.io.FileUtils; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.pentaho.marketplace.domain.model.entities.interfaces.IDomainStatusMessage; import org.pentaho.marketplace.domain.model.entities.interfaces.IPlugin; import org.pentaho.marketplace.domain.model.entities.interfaces.IPluginVersion; import org.pentaho.marketplace.domain.model.entities.interfaces.IVersionData; import org.pentaho.marketplace.domain.model.factories.interfaces.IDomainStatusMessageFactory; import org.pentaho.marketplace.domain.model.factories.interfaces.IPluginVersionFactory; import org.pentaho.marketplace.domain.model.factories.interfaces.IVersionDataFactory; import org.pentaho.marketplace.domain.services.interfaces.IPluginProvider; import org.pentaho.marketplace.domain.services.interfaces.IPluginService; import org.pentaho.marketplace.domain.services.interfaces.IRemotePluginProvider; import org.pentaho.telemetry.ITelemetryService; import org.pentaho.telemetry.TelemetryEvent; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Map; public abstract class BasePluginService implements IPluginService { //region Inner Definitions protected static class MarketplaceSecurityException extends Exception { private static final long serialVersionUID = -1852471739131561628L; } //endregion //region Constants // Error messages codes should begin with ERROR protected static final String UNAUTHORIZED_ACCESS_MESSAGE = "Unauthorized Access."; protected static final String UNAUTHORIZED_ACCESS_ERROR_CODE = "ERROR_0002_UNAUTHORIZED_ACCESS"; protected static final String NO_PLUGIN_ERROR_CODE = "ERROR_0001_NO_PLUGIN"; protected static final String FAIL_ERROR_CODE = "ERROR_0003_FAIL"; protected static final String PLUGIN_INSTALLED_CODE = "PLUGIN_INSTALLED"; protected static final String PLUGIN_UNINSTALLED_CODE = "PLUGIN_UNINSTALLED"; protected static final String KARAF_FEATURES_CONFIG_PID = "org.apache.karaf.features"; protected static final String KARAF_FEATURES_BOOT_PROPERTY_ID = "featuresBoot"; protected static final String PENTAHO_FEATURES_CONFIG_PID = "org.pentaho.features"; protected static final String PENTAHO_RUNTIME_FEATURES_PROPERTY_ID = "runtimeFeatures"; //endregion //region Properties //region logger protected Log getLogger() { return this.logger; } protected Log logger = LogFactory.getLog(this.getClass()); //endregion //region metadataPluginsProvider public IPluginProvider getMetadataPluginsProvider() { return this.metadataPluginsProvider; } protected BasePluginService setMetadataPluginsProvider(IPluginProvider provider) { this.metadataPluginsProvider = provider; return this; } private IPluginProvider metadataPluginsProvider; //endregion //region versionDataFactory public IVersionDataFactory getVersionDataFactory() { return this.versionDataFactory; } protected void setVersionDataFactory(IVersionDataFactory versionDataFactory) { this.versionDataFactory = versionDataFactory; } private IVersionDataFactory versionDataFactory; //endregion //region pluginVersionFactory public IPluginVersionFactory getPluginVersionFactory() { return pluginVersionFactory; } protected void setPluginVersionFactory(IPluginVersionFactory pluginVersionFactory) { this.pluginVersionFactory = pluginVersionFactory; } private IPluginVersionFactory pluginVersionFactory; //endregion //region karService public KarService getKarService() { return this.karService; } protected void setKarService(KarService karService) { this.karService = karService; } private KarService karService; //endregion karService //region featureService public FeaturesService getFeaturesService() { return this.featuresService; } protected void setFeaturesService(FeaturesService featuresService) { this.featuresService = featuresService; } private FeaturesService featuresService; //endregion //region telemetryService public ITelemetryService getTelemetryService() { return this.telemetryService; } protected void setTelemetryService(ITelemetryService telemetryService) { this.telemetryService = telemetryService; } private ITelemetryService telemetryService; //endregion //region getDomainStatusMessageFactory public IDomainStatusMessageFactory getDomainStatusMessageFactory() { return this.domainStatusMessageFactory; } protected BasePluginService setDomainStatusMessageFactory( IDomainStatusMessageFactory domainStatusMessageFactory) { this.domainStatusMessageFactory = domainStatusMessageFactory; return this; } private IDomainStatusMessageFactory domainStatusMessageFactory; //endregion //region serverVersion protected String getServerVersion() { return this.serverVersion; } protected BasePluginService setServerVersion(String serverVersion) { this.serverVersion = serverVersion; return this; } private String serverVersion; //endregion protected ConfigurationAdmin getConfigurationAdmin() { return this.configurationAdmin; } protected BasePluginService setConfigurationAdmin(ConfigurationAdmin configurationAdmin) { this.configurationAdmin = configurationAdmin; return this; } private ConfigurationAdmin configurationAdmin; //endregion //region Constructors protected BasePluginService(IRemotePluginProvider metadataPluginsProvider, IVersionDataFactory versionDataFactory, IPluginVersionFactory pluginVersionFactory, KarService karService, FeaturesService featuresService, ConfigurationAdmin configurationAdmin, ITelemetryService telemetryService, IDomainStatusMessageFactory domainStatusMessageFactory) { //initialize dependencies this.setMetadataPluginsProvider(metadataPluginsProvider); this.setVersionDataFactory(versionDataFactory); this.setPluginVersionFactory(pluginVersionFactory); this.setKarService(karService); this.setFeaturesService(featuresService); this.setConfigurationAdmin(configurationAdmin); this.setTelemetryService(telemetryService); this.setDomainStatusMessageFactory(domainStatusMessageFactory); } //endregion //region Methods private boolean withinParentVersion(IPluginVersion pv) { // need to compare plugin version min and max parent with system version. // replace the version of the xml url path with the current release version: String v = this.getServerVersion(); IVersionData pvMax = this.getVersionDataFactory().create(pv.getMaxParentVersion()); IVersionData pvMin = this.getVersionDataFactory().create(pv.getMinParentVersion()); IVersionData version = this.getVersionDataFactory().create(v); return version.within(pvMin, pvMax); } private Collection<IPluginVersion> getCompatibleVersionsWithParent(Iterable<IPluginVersion> versions) { Collection<IPluginVersion> compatibleVersions = new ArrayList<>(); for (IPluginVersion version : versions) { if (withinParentVersion(version)) { compatibleVersions.add(version); } } return compatibleVersions; } /** * Filters out plugins without a compatible version to server. Removes non compatible versions for the plugins which * pass the filter. */ private Map<String, IPlugin> removeNonCompatibleVersions(Iterable<IPlugin> plugins) { Map<String, IPlugin> pluginsWithCompatibleVersions = new HashMap<>(); for (IPlugin plugin : plugins) { // filter out plugin versions that are not compatible with parent version Collection<IPluginVersion> compatibleVersions = this .getCompatibleVersionsWithParent(plugin.getVersions()); // only include plugins that have versions within this release if (compatibleVersions.size() > 0) { // change available version to only compatible ones plugin.setVersions(compatibleVersions); pluginsWithCompatibleVersions.put(plugin.getId(), plugin); } } return pluginsWithCompatibleVersions; } private boolean isPluginIdValid(String pluginId) { return pluginId != null && pluginId.length() > 0 // this checks to make sure the plugin metadata isn't attempting to overwrite a folder on the system. // TODO: Test a .. encoded in UTF8, etc to see if there is a way to thwart this check && pluginId.indexOf(".") < 0; } public IPlugin getPlugin(String id) { return this.getPlugins().get(id); } // TODO: only allows one version per branch public IPluginVersion getPluginVersion(IPlugin plugin, String versionBranch) { if (versionBranch != null && versionBranch.length() > 0) { return plugin.getVersionByBranch(versionBranch); } return null; } /** * Filters plugins by plugin id */ private Map<String, IPlugin> filterPlugins(Map<String, IPlugin> plugins, Collection<String> pluginIds) { if (pluginIds.size() < 1) { return Collections.emptyMap(); } Map<String, IPlugin> filteredPlugins = new HashMap<>(); for (String pluginId : pluginIds) { IPlugin plugin = plugins.get(pluginId); if (plugin != null) { filteredPlugins.put(pluginId, plugin); } } return filteredPlugins; } /** * Sets plugins as installed as well as the installed version * * @param plugins the plugins to be marked as installed */ private void setPluginsAsInstalled(Collection<IPlugin> plugins) { for (IPlugin plugin : plugins) { plugin.setInstalled(true); IPluginVersion installedVersion = getInstalledPluginVersion(plugin); if (installedVersion != null) { plugin.setInstalledBranch(installedVersion.getBranch()); plugin.setInstalledVersion(installedVersion.getVersion()); plugin.setInstalledBuildId(installedVersion.getBuildId()); } } } private void publishTelemetryEvent(TelemetryEvent.Type eventType, IPlugin plugin, IPluginVersion version) { try { ITelemetryService telemetryService = this.getTelemetryService(); TelemetryEvent event = telemetryService.createEvent(eventType); event.getExtraInfo().put("installedPlugin", plugin.getId()); event.getExtraInfo().put("installedBranch", version.getBranch()); event.getExtraInfo().put("installedVersion", version.getVersion()); telemetryService.publishEvent(event); } catch (NoClassDefFoundError e) { this.getLogger() .debug("Failed to find class definitions. Most likely reason is reinstalling marketplace.", e); } } private IDomainStatusMessage upgradePluginAux(String pluginId, String versionBranch) { if (!hasMarketplacePermission()) { return this.getDomainStatusMessageFactory().create(UNAUTHORIZED_ACCESS_ERROR_CODE, UNAUTHORIZED_ACCESS_MESSAGE); } if (!isPluginIdValid(pluginId)) { return this.getDomainStatusMessageFactory().create(NO_PLUGIN_ERROR_CODE, "Invalid plugin id"); } IPlugin plugin = this.getPlugin(pluginId); if (plugin == null) { return this.getDomainStatusMessageFactory().create(NO_PLUGIN_ERROR_CODE, "Plugin not found"); } IPluginVersion pluginVersionToInstall = plugin.getVersionByBranch(versionBranch); if (pluginVersionToInstall == null) { return this.getDomainStatusMessageFactory().create(NO_PLUGIN_ERROR_CODE, "Plugin version for branch " + versionBranch + " not found"); } // Perhaps we are reinstalling the marketplace. // Create telemetry event and messages before closing class loader just in case. ITelemetryService telemetryService = this.getTelemetryService(); TelemetryEvent event = telemetryService.createEvent(TelemetryEvent.Type.UPGRADE); event.getExtraInfo().put("installedPlugin", plugin.getId()); event.getExtraInfo().put("installedVersion", pluginVersionToInstall.getVersion()); event.getExtraInfo().put("installedBranch", versionBranch); IDomainStatusMessage successMessage = this.domainStatusMessageFactory.create(PLUGIN_INSTALLED_CODE, plugin.getName() + " was successfully Upgraded. Please restart. \n" + plugin.getInstallationNotes()); IDomainStatusMessage upgradeInstallFailureMessage = this.domainStatusMessageFactory.create(FAIL_ERROR_CODE, "Failed to install on plugin upgrade, see log for details."); IDomainStatusMessage upgradeUninstallFailureMessage = this.domainStatusMessageFactory .create(FAIL_ERROR_CODE, "Failed to uninstall on plugin upgrade, see log for details."); // it's an upgrade, uninstall old version first if (!this.executeUninstall(plugin)) { return upgradeUninstallFailureMessage; } // install new version if (!this.executeInstall(plugin, pluginVersionToInstall)) { return upgradeInstallFailureMessage; } try { telemetryService.publishEvent(event); } catch (NoClassDefFoundError e) { this.getLogger() .debug("Failed to find class definitions. Most likely reason is reinstalling marketplace.", e); } return successMessage; } private IDomainStatusMessage installPluginAux(String pluginId, String versionBranch) throws MarketplaceSecurityException { if (!hasMarketplacePermission()) { throw new MarketplaceSecurityException(); } if (!isPluginIdValid(pluginId)) { return this.domainStatusMessageFactory.create(NO_PLUGIN_ERROR_CODE, "Invalid Plugin Id."); } IPlugin toInstall = this.getPlugin(pluginId); if (toInstall == null) { return this.domainStatusMessageFactory.create(NO_PLUGIN_ERROR_CODE, "Plugin Not Found"); } IPluginVersion versionToInstall = null; if (versionBranch != null && versionBranch.length() > 0) { versionToInstall = toInstall.getVersionByBranch(versionBranch); if (versionToInstall == null) { return this.domainStatusMessageFactory.create(NO_PLUGIN_ERROR_CODE, "Plugin version not found"); } } else { return this.domainStatusMessageFactory.create(FAIL_ERROR_CODE, "Version " + versionBranch + " not found for plugin " + pluginId + ", see log for details."); } // Perhaps we are reinstalling the marketplace. // Create telemetry event and messages before closing class loader just in case. ITelemetryService telemetryService = this.getTelemetryService(); TelemetryEvent event = telemetryService.createEvent(TelemetryEvent.Type.INSTALLATION); event.getExtraInfo().put("installedPlugin", toInstall.getId()); event.getExtraInfo().put("installedVersion", versionToInstall.getVersion()); event.getExtraInfo().put("installedBranch", versionBranch); IDomainStatusMessage successMessage = this.domainStatusMessageFactory.create(PLUGIN_INSTALLED_CODE, toInstall.getName() + " was successfully installed. Please restart your BI Server. \n" + toInstall.getInstallationNotes()); IDomainStatusMessage failureMessage = this.domainStatusMessageFactory.create(FAIL_ERROR_CODE, "Failed to execute install, see log for details."); if (!this.executeInstall(toInstall, versionToInstall)) { return failureMessage; } try { telemetryService.publishEvent(event); } catch (NoClassDefFoundError e) { this.getLogger() .debug("Failed to find class definitions. Most likely reason is reinstalling marketplace.", e); } return successMessage; } private IDomainStatusMessage uninstallPluginAux(String pluginId) throws MarketplaceSecurityException { if (!hasMarketplacePermission()) { throw new MarketplaceSecurityException(); } IPlugin toUninstall = this.getPlugin(pluginId); if (toUninstall == null) { return this.domainStatusMessageFactory.create(NO_PLUGIN_ERROR_CODE, "Plugin Not Found"); } // Perhaps we are uninstalling the marketplace. // Create telemetry event and messages before closing class loader just in case. ITelemetryService telemetryService = this.getTelemetryService(); TelemetryEvent event = telemetryService.createEvent(TelemetryEvent.Type.INSTALLATION); event.getExtraInfo().put("uninstalledPlugin", toUninstall.getId()); event.getExtraInfo().put("uninstalledPluginVersion", toUninstall.getInstalledVersion()); event.getExtraInfo().put("uninstalledPluginBranch", toUninstall.getInstalledBranch()); IDomainStatusMessage successMessage = this.domainStatusMessageFactory.create(PLUGIN_UNINSTALLED_CODE, toUninstall.getName() + " was successfully uninstalled. Please restart your BI Server."); IDomainStatusMessage failureMessage = this.domainStatusMessageFactory.create(FAIL_ERROR_CODE, "Failed to execute uninstall, see log for details."); if (!this.executeUninstall(toUninstall)) { return failureMessage; } try { telemetryService.publishEvent(event); } catch (NoClassDefFoundError e) { this.getLogger() .debug("Failed to find class definitions. Most likely reason is uninstalling marketplace.", e); } return successMessage; } //endregion //region IPluginService implementation @Override public Map<String, IPlugin> getPlugins() { Map<String, IPlugin> marketplacePlugins = this.getMetadataPluginsProvider().getPlugins(); Map<String, IPlugin> compatiblePlugins = this.removeNonCompatibleVersions(marketplacePlugins.values()); Collection<String> installedPluginIds = getInstalledPluginIds(); Map<String, IPlugin> installedPlugins = this.filterPlugins(compatiblePlugins, installedPluginIds); this.setPluginsAsInstalled(installedPlugins.values()); return compatiblePlugins; } @Override public IDomainStatusMessage installPlugin(String pluginId, String versionBranch) { try { IPlugin plugin = this.getPlugin(pluginId); if (plugin != null && plugin.isInstalled()) { return this.upgradePluginAux(pluginId, versionBranch); } else { return this.installPluginAux(pluginId, versionBranch); } } catch (MarketplaceSecurityException e) { this.getLogger().debug(e.getMessage(), e); return this.domainStatusMessageFactory.create(UNAUTHORIZED_ACCESS_ERROR_CODE, UNAUTHORIZED_ACCESS_MESSAGE); } } @Override public IDomainStatusMessage uninstallPlugin(String pluginId) { try { return uninstallPluginAux(pluginId); } catch (MarketplaceSecurityException e) { this.getLogger().debug(e.getMessage(), e); return this.domainStatusMessageFactory.create(UNAUTHORIZED_ACCESS_ERROR_CODE, UNAUTHORIZED_ACCESS_MESSAGE); } } //endregion protected boolean executeOsgiInstallViaKarService(IPlugin plugin, IPluginVersion versionToInstall) { if (versionToInstall.isOsgi()) { this.getLogger().debug("## Install Osgi Plugin ##"); try { URI uri = new URL(versionToInstall.getDownloadUrl()).toURI(); this.getKarService().install(uri); // TODO: check if it was successful or not return true; } catch (Exception e) { this.getLogger().warn("Failed to install OSGi plugin.", e); return false; } } return false; } private String getKarafDeployFolder() { //TODO: hardcoded deploy folder. Check for better alternative return System.getProperty("karaf.base") + File.separator + "deploy"; } protected boolean executeOsgiInstall(IPlugin plugin, IPluginVersion versionToInstall) { if (versionToInstall.isOsgi()) { this.getLogger().debug("Installing Osgi Plugin " + plugin.getId()); try { String deployFolderName = this.getKarafDeployFolder(); String downloadUrl = versionToInstall.getDownloadUrl(); //String karName = FilenameUtils.getName( downloadUrl ); File dlKarFile = new File(deployFolderName + File.separator + plugin.getId() + ".kar"); FileUtils.copyURLToFile(new URL(downloadUrl), dlKarFile); // TODO: check if it was successful or not return true; } catch (Exception e) { this.getLogger().warn("Failed to install OSGi plugin " + plugin.getId(), e); return false; } } return false; } protected boolean executeOsgiUninstallViaKarService(IPlugin plugin) { this.getLogger().debug("Uninstalling Osgi Plugin " + plugin.getId()); try { this.getKarService().uninstall(plugin.getId()); // TODO: check if it was successful or not return true; } catch (Exception e) { this.getLogger().warn("Failed to uninstall OSGi plugin " + plugin.getId(), e); return false; } } protected boolean executeOsgiUninstall(IPlugin plugin) { String pluginId = plugin.getId(); this.removeFeatureFromKarafBoot(pluginId); try { this.getFeaturesService().uninstallFeature(pluginId); } catch (Exception e) { this.getLogger() .debug("No installed feature found with name " + pluginId + " when uninstalling OSGI plugin."); } // remove KAR file from deploy folder if it exists String deployFolder = this.getKarafDeployFolder(); File karFile = new File(deployFolder + File.separator + pluginId + ".kar"); if (karFile.exists() && karFile.isFile()) { return FileUtils.deleteQuietly(karFile); } return true; } private void removeFeatureFromKarafBoot(String featureName) { this.removeFeatureFromKarafBoot(featureName, KARAF_FEATURES_CONFIG_PID, KARAF_FEATURES_BOOT_PROPERTY_ID); this.removeFeatureFromKarafBoot(featureName, PENTAHO_FEATURES_CONFIG_PID, PENTAHO_RUNTIME_FEATURES_PROPERTY_ID); } private void removeFeatureFromKarafBoot(String featureName, String configurationPid, String propertyId) { ConfigurationAdmin configurationAdmin = this.getConfigurationAdmin(); Log logger = this.getLogger(); try { Configuration configuration = configurationAdmin.getConfiguration(configurationPid); Dictionary<String, Object> properties = configuration.getProperties(); if (properties == null) { logger.debug("Configuration " + configurationPid + " has no properties."); return; } String propertyValue = (String) properties.get(propertyId); if (propertyValue == null) { logger.debug("Property " + propertyId + " not set in configuration " + configurationPid + "."); return; } String newPropertyValue = propertyValue.replaceFirst("," + featureName, ""); if (!propertyValue.equals(newPropertyValue)) { properties.put(propertyId, newPropertyValue); configuration.update(properties); } } catch (IOException e) { logger.debug("Unable to access configuration " + configurationPid + "."); } } private IPluginVersion getInstalledOsgiPluginVersion(IPlugin plugin) { this.getLogger().debug("Infer Version from installed Osgi Plugin"); // search installed features for plugin id IPluginVersion installedOsgiPluginVersion = this.getInstalledOsgiPluginVersionFromFeatures(plugin); if (installedOsgiPluginVersion == null) { // If no feature with the plugin id is found, check installed KARs installedOsgiPluginVersion = this.getInstalledOsgiPluginVersionFromKars(plugin); } return installedOsgiPluginVersion; } private IPluginVersion getInstalledOsgiPluginVersionFromKars(IPlugin plugin) { try { if (this.getKarService().list().contains(plugin.getId())) { IPluginVersion installedPluginVersion = this.getPluginVersionFactory().create(); installedPluginVersion.setIsOsgi(true); // TODO: add branch / version / buildId information that currently is not available return installedPluginVersion; } } catch (Exception e) { return null; } return null; } private IPluginVersion getInstalledOsgiPluginVersionFromFeatures(IPlugin plugin) { this.getLogger().debug("## Infer Version from Karaf features ##"); try { String pluginId = plugin.getId(); Feature feature = this.getFeaturesService().getFeature(pluginId); if (feature != null) { IPluginVersion installedPluginVersion = this.getPluginVersionFactory().create(); installedPluginVersion.setIsOsgi(true); // installedPluginVersion.setName( feature.getName() ); installedPluginVersion.setVersion(feature.getVersion()); installedPluginVersion.setBranch(null); installedPluginVersion.setBuildId(null); return installedPluginVersion; } } catch (Exception e) { this.getLogger().warn("Failed to infer version of installed OSGi plugin from features.", e); return null; } return null; } private IPluginVersion getInstalledPluginVersion(IPlugin plugin) { IPluginVersion osgiPluginVersion = this.getInstalledOsgiPluginVersion(plugin); if (osgiPluginVersion != null) { return osgiPluginVersion; } else { return this.getInstalledNonOsgiPluginVersion(plugin); } } private Collection<String> getInstalledOsgiPluginIds() { Collection<String> potentialOsgiPluginIds = new HashSet<>(); try { for (String installedKar : this.getKarService().list()) { potentialOsgiPluginIds.add(installedKar); } } catch (Exception e) { } for (Feature feature : this.getFeaturesService().listInstalledFeatures()) { potentialOsgiPluginIds.add(feature.getName()); } return potentialOsgiPluginIds; } private Collection<String> getInstalledPluginIds() { Collection<String> installedPluginIds = this.getInstalledOsgiPluginIds(); installedPluginIds.addAll(this.getInstalledNonOsgiPluginIds()); return installedPluginIds; } private boolean executeInstall(IPlugin plugin, IPluginVersion version) { if (version.isOsgi()) { return this.executeOsgiInstall(plugin, version); } else { // before install, close class loader in case it's a reinstall this.unloadPlugin(plugin); return this.executeNonOsgiInstall(plugin, version); } } private boolean executeUninstall(IPlugin plugin) { IPluginVersion version = this.getInstalledPluginVersion(plugin); if (version == null) { this.getLogger().debug("Did not find plugin version for installed plugin: " + plugin.getId()); return false; } if (version.isOsgi()) { return this.executeOsgiUninstall(plugin); } else { // before install, close class loader in case it's a reinstall this.unloadPlugin(plugin); return this.executeNonOsgiUninstall(plugin); } } protected abstract boolean hasMarketplacePermission(); protected abstract void unloadPlugin(IPlugin pluginId); protected abstract boolean executeNonOsgiInstall(IPlugin plugin, IPluginVersion version); protected abstract boolean executeNonOsgiUninstall(IPlugin plugin); protected abstract IPluginVersion getInstalledNonOsgiPluginVersion(IPlugin plugin); protected abstract Collection<String> getInstalledNonOsgiPluginIds(); }