/************************************************************************************* * Copyright (c) 2013 Red Hat, Inc. and others. * 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: * JBoss by Red Hat - Initial implementation. ************************************************************************************/ package org.jboss.tools.runtime.core.internal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SubProgressMonitor; import org.jboss.tools.runtime.core.RuntimeCoreActivator; import org.jboss.tools.runtime.core.model.DownloadRuntime; import org.jboss.tools.runtime.core.model.IDownloadRuntimesProvider; import org.jboss.tools.runtime.core.model.IRuntimeDetectionResolution; import org.jboss.tools.runtime.core.model.IRuntimeDetectionResolutionProvider; import org.jboss.tools.runtime.core.model.IRuntimeDetector; import org.jboss.tools.runtime.core.model.IRuntimeDetectorDelegate; import org.jboss.tools.runtime.core.model.IRuntimeInstaller; import org.jboss.tools.runtime.core.model.RuntimeDefinition; import org.jboss.tools.runtime.core.model.RuntimeDetectionProblem; public class RuntimeExtensionManager { // Extension points private static final String RUNTIME_DETECTOR_EXTENSION_ID = "org.jboss.tools.runtime.core.runtimeDetectors"; //$NON-NLS-1$ public static final String DOWNLOAD_RUNTIMES_PROVIDER_EXTENSION_ID = "org.jboss.tools.runtime.core.downloadRuntimeProvider"; //$NON-NLS-1$ private static final String RUNTIME_INSTALLER_EXTENSION_ID = "org.jboss.tools.runtime.core.runtimeInstaller"; //$NON-NLS-1$ private static final String RUNTIME_PROBLEM_RESOLUTION_EXTENSION_ID = "org.jboss.tools.runtime.core.runtimeDetectionResolutionProvider"; //$NON-NLS-1$ // Member variables private IDownloadRuntimesProvider[] downloadRuntimeProviders = null; private Set<IRuntimeDetector> runtimeDetectors; // property keyys for download runtime provider ext pt. private static final String NAME = "name"; //$NON-NLS-1$ private static final String CLAZZ = "class"; //$NON-NLS-1$ // property keys for runtime detector ext.pt. private static final String PREFERENCE_ID = "preferenceId"; //$NON-NLS-1$ private static final String ID = "id"; //$NON-NLS-1$ private static final String ENABLED = "enabled"; //$NON-NLS-1$ private static final String PRIORITY = "priority"; //$NON-NLS-1$ private static RuntimeExtensionManager manager = null; public static RuntimeExtensionManager getDefault() { if( manager == null ) manager = new RuntimeExtensionManager(); return manager; } /** * This method will load runtime detectors from the extension * point, AND set its enablement based on values from the * preferences. * * Protected only for testing purposes * * @return */ protected Set<IRuntimeDetector> loadInitializedRuntimeDetectors() { Set<IRuntimeDetector> tmp = loadDeclaredRuntimeDetectors(); initializeRuntimeDetectorEnablement(tmp); return tmp; } public synchronized Set<IRuntimeDetector> getRuntimeDetectors() { if (runtimeDetectors == null) { runtimeDetectors = RuntimeExtensionManager.getDefault().loadInitializedRuntimeDetectors(); } return runtimeDetectors; } public IRuntimeDetector findRuntimeDetector(String id) { for (IRuntimeDetector detector:getRuntimeDetectors()) { if (id.equals(detector.getId())) { return detector; } } return null; } private void initializeRuntimeDetectorEnablement(Set<IRuntimeDetector> set) { String[] enabledDetectors = RuntimeCorePreferences.getDefault().getEnabledRuntimeDetectors(); String[] disabledDetectors = RuntimeCorePreferences.getDefault().getDisabledRuntimeDetectors(); boolean allEnabled = false; if (enabledDetectors == null) { allEnabled = true; } enabledDetectors = (enabledDetectors == null ? new String[0] : enabledDetectors); disabledDetectors = (disabledDetectors == null ? new String[0] : disabledDetectors); List<String> enabled = Arrays.asList(enabledDetectors); List<String> disabled = Arrays.asList(disabledDetectors); for (IRuntimeDetector detector : set) { if( allEnabled || enabled.contains(detector.getId())) { ((RuntimeDetector)detector).setEnabled(true); } else if( disabled.contains(detector.getId())) { ((RuntimeDetector)detector).setEnabled(false); } // Else use the default for the (assumed new) detector } } /** * This method will do a full load and actually instantiate the classes * It will *NOT* set the enablement for the runtime detectors * * This method should not be public :( * @return */ public Set<IRuntimeDetector> loadDeclaredRuntimeDetectors() { Set<IRuntimeDetector> declared = new TreeSet<IRuntimeDetector>(); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry .getExtensionPoint(RUNTIME_DETECTOR_EXTENSION_ID); IExtension[] extensions = extensionPoint.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension extension = extensions[i]; IConfigurationElement[] configurationElements = extension .getConfigurationElements(); for (int j = 0; j < configurationElements.length; j++) { IRuntimeDetector dec = loadOneDeclaredRuntimeDetector(configurationElements[j]); if( !declared.contains(dec)) { declared.add(dec); } } } return declared; } // This method will load one detector from a configuration element private IRuntimeDetector loadOneDeclaredRuntimeDetector(IConfigurationElement configurationElement) { String name = configurationElement.getAttribute(NAME); String preferenceId = configurationElement.getAttribute(PREFERENCE_ID); String id = configurationElement.getAttribute(ID); String priorityString = configurationElement .getAttribute(PRIORITY); String enabled = configurationElement.getAttribute(ENABLED); int priority; try { priority = Integer.parseInt(priorityString); } catch (Exception ex) { priority = Integer.MAX_VALUE; } IRuntimeDetectorDelegate delegate = null; try { delegate = (IRuntimeDetectorDelegate) configurationElement.createExecutableExtension(CLAZZ); RuntimeDetector detector = new RuntimeDetector( name, id, preferenceId, priority, delegate); detector.setEnabled(Boolean.parseBoolean(enabled)); return detector; } catch (CoreException e) { RuntimeCoreActivator.pluginLog().logError(e); return new InvalidRuntimeDetector(name, id, preferenceId, priority); } } /** * This method does not benefit from progress monitors. * Use at your own risk. * @return */ public Map<String, DownloadRuntime> getDownloadRuntimes() { return getDownloadRuntimes( new NullProgressMonitor() ); } private Map<String, DownloadRuntime> cachedDownloadRuntimes = null; public Map<String, DownloadRuntime> getDownloadRuntimes(IProgressMonitor monitor) { // Cache for now, since we still fetch remote files // Once fetching remote files is removed, we no longer // need to cache this, and in fact should not. // Individual providers can cache on their own, or not, a they wish // We still return the actual data map. This is pretty bad. if( cachedDownloadRuntimes == null ) { Map<String, DownloadRuntime> tmp = loadDownloadRuntimes(monitor); if( monitor.isCanceled()) { // Do not cache, as the list is incomplete and should be loaded again. return tmp; } cachedDownloadRuntimes = tmp; } return cachedDownloadRuntimes; } /** * This method may be long-running. This signature is not reccommended for use. * Please use hte signature with a progress monitor instead * @deprecated * @param id * @return */ public DownloadRuntime findDownloadRuntime(String id) { Map<String, DownloadRuntime> runtimes = getDownloadRuntimes(); return findDownloadRuntime(id, new NullProgressMonitor()); } public DownloadRuntime findDownloadRuntime(String id, IProgressMonitor monitor) { Map<String, DownloadRuntime> runtimes = getDownloadRuntimes(monitor); return findDownloadRuntime(id, runtimes); } private DownloadRuntime findDownloadRuntime(String id, Map<String, DownloadRuntime> runtimes) { if( id == null ) return null; DownloadRuntime rt = runtimes.get(id); if( rt != null ) return rt; Collection<DownloadRuntime> rts = runtimes.values(); Iterator<DownloadRuntime> i = rts.iterator(); while(i.hasNext()) { DownloadRuntime i1 = i.next(); Object propVal = i1.getProperty(DownloadRuntime.PROPERTY_ALTERNATE_ID); if( propVal != null ) { if( propVal instanceof String[]) { String[] propVal2 = (String[]) propVal; for( int it = 0; it < propVal2.length; it++ ) { if( id.equals(propVal2[it])) return i1; } } else if( propVal instanceof String ) { if( id.equals(propVal)) return i1; } } } return null; } private Map<String, DownloadRuntime> loadDownloadRuntimes(IProgressMonitor monitor) { HashMap<String, DownloadRuntime> tmp = new HashMap<String, DownloadRuntime>(); monitor.beginTask("Loading Downloadable Runtimes", 300); loadDownloadableRuntimesFromProviders(tmp, new SubProgressMonitor(monitor, 300)); return tmp; } /** * This method is NOT PUBLIC. * It is only exposed for TESTING purposes. * * @param map */ public void loadDownloadableRuntimesFromProviders(Map<String, DownloadRuntime> map, IProgressMonitor monitor) { IDownloadRuntimesProvider[] providers = getDownloadRuntimeProviders(); monitor.beginTask("Loading Download Runtime Providers", providers.length * 100); for( int i = 0; i < providers.length && !monitor.isCanceled(); i++ ) { IProgressMonitor inner = new SubProgressMonitor(monitor, 100); DownloadRuntime[] runtimes = providers[i].getDownloadableRuntimes(null, inner); if( runtimes != null ) { for( int j = 0; j < runtimes.length; j++ ) { if( runtimes[j] != null ) map.put(runtimes[j].getId(), runtimes[j]); } } inner.done(); } } private IDownloadRuntimesProvider[] getDownloadRuntimeProviders() { if( downloadRuntimeProviders == null ) downloadRuntimeProviders = loadDownloadRuntimeProviders(); return downloadRuntimeProviders; } private IDownloadRuntimesProvider[] loadDownloadRuntimeProviders() { ArrayList<IDownloadRuntimesProvider> list = new ArrayList<IDownloadRuntimesProvider>(); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry .getExtensionPoint(DOWNLOAD_RUNTIMES_PROVIDER_EXTENSION_ID); IExtension[] extensions = extensionPoint.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension extension = extensions[i]; IConfigurationElement[] configurationElements = extension .getConfigurationElements(); for (int j = 0; j < configurationElements.length; j++) { IConfigurationElement configurationElement = configurationElements[j]; try { IDownloadRuntimesProvider provider = (IDownloadRuntimesProvider)configurationElement.createExecutableExtension(CLAZZ); list.add(provider); } catch(CoreException ce) { RuntimeCoreActivator.pluginLog().logError("Error loading download runtime provider", ce); } } } return (IDownloadRuntimesProvider[]) list.toArray(new IDownloadRuntimesProvider[list.size()]); } private static class RuntimeInstallerWrapper { private String id; private IRuntimeInstaller installer; public RuntimeInstallerWrapper(String id, IRuntimeInstaller installer) { this.id = id; this.installer = installer; } public String getId() { return id; } public IRuntimeInstaller getInstaller() { return installer; } } private ArrayList<RuntimeInstallerWrapper> installers; private ArrayList<RuntimeInstallerWrapper> loadInstallers() { ArrayList<RuntimeInstallerWrapper> list = new ArrayList<RuntimeInstallerWrapper>(); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(RUNTIME_INSTALLER_EXTENSION_ID); IExtension[] extensions = extensionPoint.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension extension = extensions[i]; IConfigurationElement[] configurationElements = extension.getConfigurationElements(); for (int j = 0; j < configurationElements.length; j++) { IConfigurationElement configurationElement = configurationElements[j]; try { IRuntimeInstaller installer = (IRuntimeInstaller)configurationElement.createExecutableExtension(CLAZZ); String id = configurationElement.getAttribute("id"); list.add(new RuntimeInstallerWrapper(id, installer)); } catch(CoreException ce) { RuntimeCoreActivator.pluginLog().logError("Error loading runtime installer", ce); } } } return list; } /** * Get a runtime installer by the given id. * * @param id * @return */ public IRuntimeInstaller getRuntimeInstaller(String id) { if( installers == null ) { installers = loadInstallers(); } Iterator<RuntimeInstallerWrapper> it = installers.iterator(); while(it.hasNext()) { RuntimeInstallerWrapper w = it.next(); if(id.equals(w.getId())) { return w.getInstaller(); } } return null; } private ArrayList<ProblemResolutionProviderWrapper> problemResolutionProviders; private ArrayList<ProblemResolutionProviderWrapper> loadProblemResolvers() { ArrayList<ProblemResolutionProviderWrapper> list = new ArrayList<ProblemResolutionProviderWrapper>(); IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry.getExtensionPoint(RUNTIME_PROBLEM_RESOLUTION_EXTENSION_ID); IExtension[] extensions = extensionPoint.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension extension = extensions[i]; IConfigurationElement[] configurationElements = extension.getConfigurationElements(); for (int j = 0; j < configurationElements.length; j++) { IConfigurationElement configurationElement = configurationElements[j]; try { IRuntimeDetectionResolutionProvider provider = (IRuntimeDetectionResolutionProvider)configurationElement.createExecutableExtension(CLAZZ); String filter = configurationElement.getAttribute("runtimeDetectorId"); String weight = configurationElement.getAttribute("weight"); int weightInt = 10; if( weight != null ) { try { weightInt = Integer.parseInt(weight); } catch(NumberFormatException nfe) { // ignore } } list.add(new ProblemResolutionProviderWrapper(weightInt, filter, provider)); } catch(CoreException ce) { RuntimeCoreActivator.pluginLog().logError("Error loading runtime problem resolution provider", ce); } } } list.sort(new Comparator<ProblemResolutionProviderWrapper>() { public int compare(ProblemResolutionProviderWrapper arg0, ProblemResolutionProviderWrapper arg1) { return arg0.getWeight() - arg1.getWeight(); }}); return list; } public IRuntimeDetectionResolution[] findResolutions(RuntimeDetectionProblem problem, RuntimeDefinition def) { if( problemResolutionProviders == null ) { problemResolutionProviders = loadProblemResolvers(); } IRuntimeDetector detector = def.getDetector(); String detectorId = detector == null ? null : detector.getId(); Iterator<ProblemResolutionProviderWrapper> it = problemResolutionProviders.iterator(); ArrayList<IRuntimeDetectionResolution> ret = new ArrayList<IRuntimeDetectionResolution>(); while(it.hasNext()) { ProblemResolutionProviderWrapper wrap = it.next(); if( detectorId == null || wrap.getDetectorFilter() == null || wrap.getDetectorFilter().equals(detectorId)) { IRuntimeDetectionResolution[] resolutions = wrap.getProvider().getResolutions(problem, def); if( resolutions != null ) { ret.addAll(Arrays.asList(resolutions)); } } } return (IRuntimeDetectionResolution[]) ret.toArray(new IRuntimeDetectionResolution[ret.size()]); } }