/******************************************************************************* * Copyright (c) 2012 - 2014 Pivotal Software, 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: * Pivotal Software, Inc. - initial API and implementation *******************************************************************************/ package org.springsource.ide.eclipse.commons.core; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; 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.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; import org.osgi.framework.Version; import org.osgi.service.prefs.BackingStoreException; import org.springsource.ide.eclipse.commons.internal.core.CorePlugin; /** * Provides access to externalized resources such as urls. Resources are * specified through an extension point. * * @author Steffen Pingel * @author Christian Dupuis */ public class ResourceProvider { public static final String RECORD_SEPARATOR_PATTERN = "[\\r\\n\\s]"; public static final String FIELD_SEPARATOR = "|"; public static final String FIELD_SEPARATOR_PATTERN = "\\|"; public static final String RECORD_SEPARATOR = "\n"; public static class Property { public String type; private String id; private String label; private String defaultValue; private boolean multiValue; private boolean userConfigurable; private String contributedValue; private final ResourceProvider provider; private Property(ResourceProvider provider) { this.provider = provider; } public String getDefaultValue() { String value = contributedValue; if (value == null) { value = defaultValue; } return value; } public String getLabel() { return label; } public String getValue() { String value = provider.getPreferences().get(id, null); if (value == null) { value = contributedValue; } if (value == null) { value = defaultValue; } return value; } public boolean isMultiValue() { return multiValue; } public boolean isUserConfigurable() { return userConfigurable; } public void setValue(String value) { provider.getPreferences().put(id, value); try { provider.getPreferences().flush(); } catch (BackingStoreException e) { StatusHandler.log(new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, "Error occured while saving preferences", e)); } } } private static class ExtensionPointReader { private static final String ATTRIBUTE_ID = "id"; private static final String ATTRIBUTE_VALUE = "value"; private static final String ATTRIBUTE_LABEL = "label"; private static final String ATTRIBUTE_TYPE = "type"; private static final String ATTRIBUTE_MULTI_VALUE = "multiValue"; private static final String ATTRIBUTE_DEFAULT_VALUE = "defaultValue"; private static final String ATTRIBUTE_USER_CONFIGURABLE = "userConfigurable"; private static final String ELEMENT_URL = "url"; private static final String ELEMENT_PROPERTY = "propertyDefinition"; private static final String EXTENSION_ID_REFERENCES = "com.springsource.sts.core.resources"; private final Map<String, String> valueByKey = new HashMap<String, String>(); private final Map<String, Property> propertyById = new HashMap<String, Property>(); public void read(ResourceProvider resourceProvider) { IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint extensionPoint = registry .getExtensionPoint(EXTENSION_ID_REFERENCES); IExtension[] extensions = extensionPoint.getExtensions(); // read property definitions for (IExtension extension : extensions) { IConfigurationElement[] elements = extension .getConfigurationElements(); for (IConfigurationElement element : elements) { if (element.getName().compareTo(ELEMENT_PROPERTY) == 0) { Property p = new Property(resourceProvider); p.id = element.getAttribute(ATTRIBUTE_ID); p.label = element.getAttribute(ATTRIBUTE_LABEL); p.defaultValue = element .getAttribute(ATTRIBUTE_DEFAULT_VALUE); p.multiValue = Boolean.parseBoolean(element .getAttribute(ATTRIBUTE_MULTI_VALUE)); p.userConfigurable = Boolean.parseBoolean(element .getAttribute(ATTRIBUTE_USER_CONFIGURABLE)); p.type = element.getAttribute(ATTRIBUTE_TYPE); propertyById.put(p.id, p); } } } // read contributed definitions for (IExtension extension : extensions) { IConfigurationElement[] elements = extension .getConfigurationElements(); for (IConfigurationElement element : elements) { if (element.getName().compareTo(ELEMENT_URL) == 0) { String key = element.getAttribute(ATTRIBUTE_ID); String value = element.getAttribute(ATTRIBUTE_VALUE); valueByKey.put(key, value); Property p = propertyById.get(key); if (p == null) { // property was not defined explicitly p = new Property(resourceProvider); p.id = key; p.label = ""; propertyById.put(p.id, p); } p.contributedValue = value; } } } } } private final IEclipsePreferences preferences; private static ResourceProvider instance = new ResourceProvider(); public static ResourceProvider getInstance() { return instance; } public static String getUrl(String key) { return getUrls(key)[0]; } public static String[] getUrls(String key) { String value = instance.getValue(key); if (value == null) { throw new RuntimeException(NLS.bind( "No URL found for key: ''{0}''", key)); } if (value.isEmpty()) { return new String[0]; } // Post process the urls to replace UUID and version number placeholders if (value.contains("%UUID%")) { value = value.replace("%UUID%", CorePlugin.getUUID()); } if (value.contains("%VERSION%") || value.contains("%SHORT_VERSION%")) { Bundle bundle = CorePlugin.getDefault().getBundle(); Version version = new Version((String) bundle.getHeaders().get( "Bundle-Version")); //$NON-NLS-1$ value = value.replace("%VERSION%", version.toString()); value = value.replace("%SHORT_VERSION%", version.getMajor() + "." + version.getMinor()); } String[] values = value.split(RECORD_SEPARATOR_PATTERN); return discardLocationNames(values); } private static String[] discardLocationNames(String[] values) { for (int i = 0; i < values.length; i++) { String nameUrlString = values[i]; String[] nameUrlStrings = nameUrlString .split(FIELD_SEPARATOR_PATTERN); if (nameUrlStrings.length == 2) { String url = nameUrlStrings[1]; values[i] = url; } } return values; } private final Map<String, Property> propertyById; private final List<PropertyChangeListener> listeners; private ResourceProvider() { this.listeners = new CopyOnWriteArrayList<PropertyChangeListener>(); this.preferences = new InstanceScope().getNode(CorePlugin.PLUGIN_ID); this.preferences .addPreferenceChangeListener(new IPreferenceChangeListener() { public void preferenceChange(PreferenceChangeEvent event) { Property p = propertyById.get(event.getKey()); if (p != null) { for (PropertyChangeListener listener : listeners) { listener.propertyChange(new PropertyChangeEvent( ResourceProvider.this, p.id, event .getOldValue(), event .getNewValue())); } } } }); ExtensionPointReader reader = new ExtensionPointReader(); reader.read(this); this.propertyById = reader.propertyById; } public void addPropertyChangeListener(PropertyChangeListener listener) { listeners.add(listener); } public IEclipsePreferences getPreferences() { return preferences; } public Collection<Property> getProperties() { return Collections.unmodifiableCollection(propertyById.values()); } public Property getProperty(String id) { return propertyById.get(id); } public void removePropertyChangeListener(PropertyChangeListener listener) { listeners.remove(listener); } private String getValue(String key) { Property p = propertyById.get(key); return (p != null) ? p.getValue() : null; } }