blob: b3a4ac50ce0285cc161e4b8bdc7fa802027016eb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.preferences;
import java.lang.ref.WeakReference;
import java.util.*;
import org.eclipse.core.internal.preferences.exchange.ILegacyPreferences;
import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Bundle;
/**
* Class which handles all registry-related work for the preferences. This code has
* been separated into a separate class to ensure that the preferences will be able
* to run without the registry being present.
*/
public class PreferenceServiceRegistryHelper implements IRegistryChangeListener {
private static final String ELEMENT_INITIALIZER = "initializer"; //$NON-NLS-1$
private static final String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
private static final String ATTRIBUTE_CLASS = "class"; //$NON-NLS-1$
private static final String ELEMENT_SCOPE = "scope"; //$NON-NLS-1$
private static final String ELEMENT_MODIFIER = "modifier"; //$NON-NLS-1$
// Store this around for performance
private final static IExtension[] EMPTY_EXTENSION_ARRAY = new IExtension[0];
private static final Map scopeRegistry = Collections.synchronizedMap(new HashMap());
private ListenerList modifyListeners;
private PreferencesService service;
private IExtensionRegistry registry;
/*
* Create and return an IStatus object with ERROR severity and the
* given message and exception.
*/
private static IStatus createStatusError(String message, Exception e) {
return new Status(IStatus.ERROR, PrefsMessages.OWNER_NAME, IStatus.ERROR, message, e);
}
/*
* Create and return an IStatus object with WARNING severity and the
* given message and exception.
*/
private static IStatus createStatusWarning(String message, Exception e) {
return new Status(IStatus.WARNING, PrefsMessages.OWNER_NAME, IStatus.WARNING, message, e);
}
/*
* Log the given status.
*/
private static void log(IStatus status) {
RuntimeLog.log(status);
}
/*
* Constructor for the class.
*/
public PreferenceServiceRegistryHelper(PreferencesService service, Object registryObject) {
super();
this.service = service;
this.registry = (IExtensionRegistry) registryObject;
initializeScopes();
registry.addRegistryChangeListener(this);
}
void stop() {
registry.removeRegistryChangeListener(this);
}
/*
* Add the given configuration element into our list of preference modify listeners.
*/
private void addModifyListener(IConfigurationElement element) {
String key = element.getAttribute(ATTRIBUTE_CLASS);
if (key == null) {
String message = NLS.bind(PrefsMessages.preferences_missingClassAttribute, element.getDeclaringExtension().getUniqueIdentifier());
log(new Status(IStatus.ERROR, PrefsMessages.OWNER_NAME, IStatus.ERROR, message, null));
return;
}
try {
Object listener = element.createExecutableExtension(ATTRIBUTE_CLASS);
if (!(listener instanceof PreferenceModifyListener)) {
log(new Status(IStatus.ERROR, PrefsMessages.OWNER_NAME, IStatus.ERROR, PrefsMessages.preferences_classCastListener, null));
return;
}
modifyListeners.add(listener);
} catch (CoreException e) {
log(e.getStatus());
}
}
/*
* Apply the runtime defaults for the bundle with the given name. Check
* to see if there is a preference initializer registered and if so, then run it.
* Otherwise call the legacy Plugin preference initialization code.
*/
public WeakReference applyRuntimeDefaults(String name, WeakReference pluginReference) {
IExtension[] extensions = getPrefExtensions();
if (extensions.length == 0) {
if (EclipsePreferences.DEBUG_PREFERENCE_GENERAL)
PrefsMessages.message("Skipping runtime default preference customization."); //$NON-NLS-1$
return null;
}
boolean foundInitializer = false;
for (int i = 0; i < extensions.length; i++) {
IConfigurationElement[] elements = extensions[i].getConfigurationElements();
for (int j = 0; j < elements.length; j++)
if (ELEMENT_INITIALIZER.equals(elements[j].getName())) {
if (name.equals(elements[j].getContributor().getName())) {
if (EclipsePreferences.DEBUG_PREFERENCE_GENERAL) {
IExtension theExtension = elements[j].getDeclaringExtension();
String extensionNamespace = theExtension.getContributor().getName();
Bundle underlyingBundle = PreferencesOSGiUtils.getDefault().getBundle(extensionNamespace);
String ownerName;
if (underlyingBundle != null)
ownerName = underlyingBundle.getSymbolicName();
else
ownerName = extensionNamespace;
PrefsMessages.message("Running default preference customization as defined by: " + ownerName); //$NON-NLS-1$
}
runInitializer(elements[j]);
// don't return yet in case we have multiple initializers registered
foundInitializer = true;
}
}
}
if (foundInitializer)
return null;
// TODO this means that we don't call the legacy Plugin code if the registry isn't present.
// I don't think this is the desired behaviour
// Do legacy plugin preference initialization
Object plugin = pluginReference.get();
ILegacyPreferences initService = PreferencesOSGiUtils.getDefault().getLegacyPreferences();
if (initService != null)
plugin = initService.init(plugin, name);
return new WeakReference(plugin);
}
/*
* Create a new child node with the given parent. Look up the name
* in the registry as it may map to a configuration element. This is done
* for lazy initialization of user-contributed scopes.
*/
public IEclipsePreferences createNode(RootPreferences parent, String name) {
IScope scope = null;
Object value = scopeRegistry.get(name);
if (value instanceof IConfigurationElement) {
try {
scope = (IScope) ((IConfigurationElement) value).createExecutableExtension(ATTRIBUTE_CLASS);
scopeRegistry.put(name, scope);
} catch (ClassCastException e) {
log(createStatusError(PrefsMessages.preferences_classCastScope, e));
return new EclipsePreferences(parent, name);
} catch (CoreException e) {
log(e.getStatus());
return new EclipsePreferences(parent, name);
}
} else
scope = (IScope) value;
return scope.create(parent, name);
}
/*
* Return a list of the preference modify listeners. They are called during preference
* import and given the chance to modify the imported tree.
*/
public PreferenceModifyListener[] getModifyListeners() {
if (modifyListeners == null) {
modifyListeners = new ListenerList();
IExtension[] extensions = getPrefExtensions();
for (int i = 0; i < extensions.length; i++) {
IConfigurationElement[] elements = extensions[i].getConfigurationElements();
for (int j = 0; j < elements.length; j++)
if (ELEMENT_MODIFIER.equalsIgnoreCase(elements[j].getName()))
addModifyListener(elements[j]);
}
}
Object[] source = modifyListeners.getListeners();
PreferenceModifyListener[] result = new PreferenceModifyListener[source.length];
System.arraycopy(source, 0, result, 0, source.length);
return result;
}
/*
* Return a list of the extensions which are plugged into the preference
* extension point.
*/
private IExtension[] getPrefExtensions() {
IExtension[] extensionsOld = EMPTY_EXTENSION_ARRAY;
IExtension[] extensionsNew = EMPTY_EXTENSION_ARRAY;
// "old"
IExtensionPoint pointOld = registry.getExtensionPoint(IPreferencesConstants.RUNTIME_NAME, IPreferencesConstants.PT_PREFERENCES);
if (pointOld != null)
extensionsOld = pointOld.getExtensions();
// "new"
IExtensionPoint pointNew = registry.getExtensionPoint(IPreferencesConstants.PREFERS_NAME, IPreferencesConstants.PT_PREFERENCES);
if (pointNew != null)
extensionsNew = pointNew.getExtensions();
// combine
IExtension[] extensions = new IExtension[extensionsOld.length + extensionsNew.length];
System.arraycopy(extensionsOld, 0, extensions, 0, extensionsOld.length);
System.arraycopy(extensionsNew, 0, extensions, extensionsOld.length, extensionsNew.length);
if (extensions.length == 0) {
if (EclipsePreferences.DEBUG_PREFERENCE_GENERAL)
PrefsMessages.message("No extensions for org.eclipse.core.contenttype."); //$NON-NLS-1$
}
return extensions;
}
/*
* See who is plugged into the extension point.
*/
private void initializeScopes() {
IExtension[] extensions = getPrefExtensions();
for (int i = 0; i < extensions.length; i++) {
IConfigurationElement[] elements = extensions[i].getConfigurationElements();
for (int j = 0; j < elements.length; j++)
if (ELEMENT_SCOPE.equalsIgnoreCase(elements[j].getName()))
scopeAdded(elements[j]);
}
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
*/
public void registryChanged(IRegistryChangeEvent event) {
IExtensionDelta[] deltasOld = event.getExtensionDeltas(IPreferencesConstants.RUNTIME_NAME, IPreferencesConstants.PT_PREFERENCES);
IExtensionDelta[] deltasNew = event.getExtensionDeltas(IPreferencesConstants.PREFERS_NAME, IPreferencesConstants.PT_PREFERENCES);
IExtensionDelta[] deltas = new IExtensionDelta[deltasOld.length + deltasNew.length];
System.arraycopy(deltasOld, 0, deltas, 0, deltasOld.length);
System.arraycopy(deltasNew, 0, deltas, deltasOld.length, deltasNew.length);
if (deltas.length == 0)
return;
// dynamically adjust the registered scopes
for (int i = 0; i < deltas.length; i++) {
IConfigurationElement[] elements = deltas[i].getExtension().getConfigurationElements();
for (int j = 0; j < elements.length; j++) {
switch (deltas[i].getKind()) {
case IExtensionDelta.ADDED :
if (ELEMENT_SCOPE.equalsIgnoreCase(elements[j].getName()))
scopeAdded(elements[j]);
break;
case IExtensionDelta.REMOVED :
String scope = elements[j].getAttribute(ATTRIBUTE_NAME);
if (scope != null)
scopeRemoved(scope);
break;
}
}
}
// initialize the preference modify listeners
modifyListeners = null;
}
/*
* Run the preference initializer as specified by the given configuration element.
*/
private void runInitializer(IConfigurationElement element) {
AbstractPreferenceInitializer initializer = null;
try {
initializer = (AbstractPreferenceInitializer) element.createExecutableExtension(ATTRIBUTE_CLASS);
initializer.initializeDefaultPreferences();
} catch (ClassCastException e) {
IStatus status = new Status(IStatus.ERROR, PrefsMessages.OWNER_NAME, IStatus.ERROR, PrefsMessages.preferences_invalidExtensionSuperclass, e);
log(status);
} catch (CoreException e) {
log(e.getStatus());
}
}
/*
* A preference scope defined by the given element was added to the extension
* registry. Add it to our registry and make it a child of the root.
*/
private void scopeAdded(IConfigurationElement element) {
String key = element.getAttribute(ATTRIBUTE_NAME);
if (key == null) {
String message = NLS.bind(PrefsMessages.preferences_missingScopeAttribute, element.getDeclaringExtension().getUniqueIdentifier());
log(createStatusWarning(message, null));
return;
}
scopeRegistry.put(key, element);
((RootPreferences) service.getRootNode()).addChild(key, null);
}
/*
* A preference scope with the given name was removed from the extension
* registry. Remove the node and its children from the preference tree.
*/
private void scopeRemoved(String key) {
IEclipsePreferences node = (IEclipsePreferences) ((RootPreferences) service.getRootNode()).getNode(key, false);
if (node != null)
((RootPreferences) service.getRootNode()).removeNode(node);
else
((RootPreferences) service.getRootNode()).removeNode(key);
scopeRegistry.remove(key);
}
}