/******************************************************************************* * Copyright (c) 2005-2008 Polarion Software. * 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: * Alexander Gurov - Initial API and implementation *******************************************************************************/ package org.eclipse.team.svn.core.extension; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; 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.Platform; import org.eclipse.team.svn.core.SVNMessages; import org.eclipse.team.svn.core.extension.crashrecovery.IResolutionHelper; import org.eclipse.team.svn.core.extension.factory.ISVNConnectorFactory; import org.eclipse.team.svn.core.extension.factory.ThreadNameModifierFactory; import org.eclipse.team.svn.core.extension.options.IIgnoreRecommendations; import org.eclipse.team.svn.core.extension.options.IOptionProvider; import org.eclipse.team.svn.core.extension.properties.IPredefinedPropertySet; import org.eclipse.team.svn.core.extension.properties.PredefinedProperty; import org.eclipse.team.svn.core.extension.properties.PredefinedPropertySet; import org.eclipse.team.svn.core.operation.LoggedOperation; /** * Manager for extension components. Used to extend Subversive without direct dependencies. * * @author Alexander Gurov */ public class CoreExtensionsManager { public static final String EXTENSION_NAMESPACE = "org.eclipse.team.svn.core"; //$NON-NLS-1$ public static final String SVN_CONNECTOR = "svnconnector"; //$NON-NLS-1$ public static final String CORE_OPTIONS = "coreoptions"; //$NON-NLS-1$ public static final String CRASH_RECOVERY = "crashrecovery"; //$NON-NLS-1$ public static final String IGNORE_RECOMMENDATIONS = "resourceIgnoreRules"; //$NON-NLS-1$ private HashMap connectors; private HashSet validConnectors; private HashMap optionProviders = new HashMap(); private String selectedOptionProviderId; private IResolutionHelper []helpers; private IIgnoreRecommendations []ignoreRecommendations; private ArrayList svnPropertySets; private static CoreExtensionsManager instance = new CoreExtensionsManager(); private boolean disableHelpers; private boolean initialized; public static CoreExtensionsManager instance() { if (CoreExtensionsManager.instance != null && !CoreExtensionsManager.instance.initialized) { synchronized (CoreExtensionsManager.class) { if (!CoreExtensionsManager.instance.initialized) { Object []extensions = CoreExtensionsManager.loadCoreExtensions(CoreExtensionsManager.CORE_OPTIONS); HashSet inferiors = new HashSet(); for (int i = 0; i < extensions.length; i++) { IOptionProvider optProvider = (IOptionProvider)extensions[i]; String id = CoreExtensionsManager.instance.registerOptionProvider(optProvider); if (i == extensions.length - 1) { CoreExtensionsManager.instance.selectOptionProvider(id); } String []inferiorOnes = optProvider.getCoveredProviders(); if (inferiorOnes != null) { for (int k = 0; k < inferiorOnes.length; k++) { inferiors.add(inferiorOnes[k]); } } } for (int i = 0; i < extensions.length; i++) { IOptionProvider optProvider = (IOptionProvider)extensions[i]; String id = optProvider.getId(); if (!inferiors.contains(id)) { CoreExtensionsManager.instance.selectOptionProvider(id); break; } } extensions = CoreExtensionsManager.loadCoreExtensions(CoreExtensionsManager.CRASH_RECOVERY); CoreExtensionsManager.instance.helpers = Arrays.asList(extensions).toArray(new IResolutionHelper[extensions.length]); extensions = CoreExtensionsManager.loadCoreExtensions(CoreExtensionsManager.IGNORE_RECOMMENDATIONS); CoreExtensionsManager.instance.ignoreRecommendations = Arrays.asList(extensions).toArray(new IIgnoreRecommendations[extensions.length]); CoreExtensionsManager.instance.initialized = true; } PredefinedPropertySet pSet = null; CoreExtensionsManager.instance.svnPropertySets = new ArrayList(); IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(CoreExtensionsManager.EXTENSION_NAMESPACE, "svnproperties"); //$NON-NLS-1$ for (IExtension ext : extension.getExtensions()) { IConfigurationElement[] configElements = ext.getConfigurationElements(); for (IConfigurationElement element : configElements) { if (element.getName() == "svnproperty") { //$NON-NLS-1$ if (pSet == null) { pSet = new PredefinedPropertySet(); CoreExtensionsManager.instance.svnPropertySets.add(pSet); } String name = element.getAttribute("name"); //$NON-NLS-1$ String typeStr = element.getAttribute("type"); //$NON-NLS-1$ typeStr = typeStr == null ? "common" : typeStr; //$NON-NLS-1$ String revision = element.getAttribute("revision"); //$NON-NLS-1$ String group = element.getAttribute("group"); //$NON-NLS-1$ IConfigurationElement[] partNode = element.getChildren("description"); //$NON-NLS-1$ String description = partNode != null && partNode.length > 0 ? partNode[0].getValue() : ""; //$NON-NLS-1$ partNode = element.getChildren("defaultValue"); //$NON-NLS-1$ String defaultValue = partNode != null && partNode.length > 0 ? partNode[0].getValue() : ""; //$NON-NLS-1$ partNode = element.getChildren("validationRegexp"); //$NON-NLS-1$ String validationRegexp = partNode != null && partNode.length > 0 ? partNode[0].getValue() : null; int type = PredefinedProperty.TYPE_NONE; if ("file".equals(typeStr)) { //$NON-NLS-1$ type = PredefinedProperty.TYPE_FILE; } else if ("folder".equals(typeStr)) { //$NON-NLS-1$ type = PredefinedProperty.TYPE_FOLDER; } else if ("common".equals(typeStr)) { //$NON-NLS-1$ type = PredefinedProperty.TYPE_COMMON; } if (revision != null && Boolean.parseBoolean(revision)) { type |= PredefinedProperty.TYPE_REVISION; } if (group != null && Boolean.parseBoolean(group)) { type |= PredefinedProperty.TYPE_GROUP; } pSet.registerProperty(new PredefinedProperty(name, description, defaultValue, validationRegexp, type)); } else { // svnpropertyset try { CoreExtensionsManager.instance.svnPropertySets.add((IPredefinedPropertySet)element.createExecutableExtension("class")); } catch (CoreException ex) { LoggedOperation.reportError(SVNMessages.getErrorString("Error_LoadExtensions"), ex); //$NON-NLS-1$ } } } } } } return CoreExtensionsManager.instance; } public IPredefinedPropertySet getPredefinedPropertySet() { PredefinedPropertySet retVal = new PredefinedPropertySet(); for (IPredefinedPropertySet set : this.svnPropertySets) { retVal.registerProperties(set.getPredefinedProperties()); } return retVal; } public IIgnoreRecommendations []getIgnoreRecommendations() { return this.ignoreRecommendations; } public IResolutionHelper []getResolutionHelpers() { return this.disableHelpers ? new IResolutionHelper[0] : this.helpers; } public void setResolutionHelpersDisabled(boolean disable) { this.disableHelpers = disable; } public boolean isResoultionHelpersDisabled() { return this.disableHelpers; } public IOptionProvider getOptionProvider(String id) { return this.optionProviders.containsKey(id) ? this.optionProviders.get(id) : IOptionProvider.DEFAULT; } public IOptionProvider getOptionProvider() { return this.getOptionProvider(this.selectedOptionProviderId); } public void setOptionProvider(IOptionProvider optionProvider) { this.selectOptionProvider(this.registerOptionProvider(optionProvider)); } public void selectOptionProvider(String id) { this.selectedOptionProviderId = id; } public String getSelectedOptionProviderId() { return this.selectedOptionProviderId; } public String registerOptionProvider(IOptionProvider optionProvider) { this.optionProviders.put(optionProvider.getId(), optionProvider); return optionProvider.getId(); } public Collection getAccessibleClientIds() { this.initializeConnectors(); return this.connectors.keySet(); } public Collection getAccessibleClients() { this.initializeConnectors(); return this.connectors.values(); } public ISVNConnectorFactory getSVNConnectorFactory() { String id = this.getOptionProvider().getSVNConnectorId(); return this.getSVNConnectorFactory(id); } public ISVNConnectorFactory getSVNConnectorFactory(String id) { ISVNConnectorFactory retVal = this.getFirstValidConnector(id); if (retVal == null) { retVal = ISVNConnectorFactory.EMPTY; } return retVal; } public static boolean isExtensionsRegistered(String extensionPoint) { Object []extensions = CoreExtensionsManager.loadCoreExtensions(extensionPoint); return extensions != null && extensions.length > 0; } private ISVNConnectorFactory getFirstValidConnector(String id) { this.initializeConnectors(); if (this.validConnectors.contains(id)) { return this.connectors.get(id); } else if (this.validConnectors.contains(ISVNConnectorFactory.DEFAULT_ID)) { return this.connectors.get(ISVNConnectorFactory.DEFAULT_ID); } for (Iterator it = this.connectors.values().iterator(); it.hasNext(); ) { ISVNConnectorFactory connector = it.next(); if (this.validConnectors.contains(connector.getId())) { return connector; } } return null; } private CoreExtensionsManager() { } private synchronized void initializeConnectors() { if (this.connectors == null) { synchronized (this) { if (this.connectors == null) { this.connectors = new HashMap(); this.validConnectors = new HashSet(); Object []extensions = CoreExtensionsManager.loadCoreExtensions(CoreExtensionsManager.SVN_CONNECTOR); for (int i = 0; i < extensions.length; i++) { ISVNConnectorFactory factory = new ThreadNameModifierFactory((ISVNConnectorFactory)extensions[i]); try { // extension point API changed and old connectors will be declined due to version changes or AbstractMethodError. if (factory.getCompatibilityVersion().compareTo(ISVNConnectorFactory.CURRENT_COMPATIBILITY_VERSION) != 0) { continue; } } catch (Throwable ex) { continue; } this.connectors.put(factory.getId(), factory); this.validateClient(factory); } } } } } private void validateClient(ISVNConnectorFactory connector) { try { connector.createConnector().dispose(); this.validConnectors.add(connector.getId()); } catch (Throwable ex) { // do nothing } } private static Object []loadCoreExtensions(String extensionPoint) { return CoreExtensionsManager.loadExtensions(CoreExtensionsManager.EXTENSION_NAMESPACE, extensionPoint); } private static Object []loadExtensions(String namespace, String extensionPoint) { IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(namespace, extensionPoint); if (extension == null) { String errMessage = SVNMessages.formatErrorString("Error_InvalidExtensionPoint", new String[] {namespace, extensionPoint}); //$NON-NLS-1$ throw new RuntimeException(errMessage); } IExtension []extensions = extension.getExtensions(); ArrayList retVal = new ArrayList(); for (int i = 0; i < extensions.length; i++) { IConfigurationElement[] configElements = extensions[i].getConfigurationElements(); for (int j = 0; j < configElements.length; j++) { try { retVal.add(configElements[j].createExecutableExtension("class")); //$NON-NLS-1$ } catch (CoreException ex) { LoggedOperation.reportError(SVNMessages.getErrorString("Error_LoadExtensions"), ex); //$NON-NLS-1$ } } } return retVal.toArray(); } }