| /******************************************************************************* |
| * Copyright (c) 2000, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.core.internal.registry; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.lang.reflect.Array; |
| import java.net.URL; |
| import java.net.URLConnection; |
| import java.util.*; |
| import org.eclipse.core.internal.runtime.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.jobs.ISchedulingRule; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.osgi.service.datalocation.FileManager; |
| import org.eclipse.osgi.service.datalocation.Location; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * An implementation for the extension registry API. |
| */ |
| public class ExtensionRegistry implements IExtensionRegistry { |
| private EclipseBundleListener pluginBundleListener; |
| |
| private final static class ExtensionEventDispatcherJob extends Job { |
| // an "identy rule" that forces extension events to be queued |
| private final static ISchedulingRule EXTENSION_EVENT_RULE = new ISchedulingRule() { |
| public boolean contains(ISchedulingRule rule) { |
| return rule == this; |
| } |
| |
| public boolean isConflicting(ISchedulingRule rule) { |
| return rule == this; |
| } |
| }; |
| private Map deltas; |
| private Object[] listenerInfos; |
| |
| public ExtensionEventDispatcherJob(Object[] listenerInfos, Map deltas) { |
| // name not NL'd since it is a system job |
| super("Registry event dispatcher"); //$NON-NLS-1$ |
| setSystem(true); |
| this.listenerInfos = listenerInfos; |
| this.deltas = deltas; |
| // all extension event dispatching jobs use this rule |
| setRule(EXTENSION_EVENT_RULE); |
| } |
| |
| public IStatus run(IProgressMonitor monitor) { |
| MultiStatus result = new MultiStatus(Platform.PI_RUNTIME, IStatus.OK, Policy.bind("plugin.eventListenerError"), null); //$NON-NLS-1$ |
| for (int i = 0; i < listenerInfos.length; i++) { |
| ListenerInfo listenerInfo = (ListenerInfo) listenerInfos[i]; |
| if (listenerInfo.filter != null && !deltas.containsKey(listenerInfo.filter)) |
| continue; |
| try { |
| listenerInfo.listener.registryChanged(new RegistryChangeEvent(deltas, listenerInfo.filter)); |
| } catch (RuntimeException re) { |
| String message = re.getMessage() == null ? "" : re.getMessage(); //$NON-NLS-1$ |
| result.add(new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.OK, message, re)); |
| } |
| } |
| for (Iterator iter = deltas.values().iterator(); iter.hasNext();) { |
| ((RegistryDelta) iter.next()).getObjectManager().close(); |
| } |
| return result; |
| } |
| } |
| |
| class ListenerInfo { |
| String filter; |
| IRegistryChangeListener listener; |
| |
| public ListenerInfo(IRegistryChangeListener listener, String filter) { |
| this.listener = listener; |
| this.filter = filter; |
| } |
| |
| /** |
| * Used by ListenerList to ensure uniqueness. |
| */ |
| public boolean equals(Object another) { |
| return another instanceof ListenerInfo && ((ListenerInfo) another).listener == this.listener; |
| } |
| } |
| |
| public static boolean DEBUG; |
| |
| private static final String OPTION_DEBUG_EVENTS_EXTENSION = "org.eclipse.core.runtime/registry/debug/events/extension"; //$NON-NLS-1$ |
| |
| // used to enforce concurrent access policy for readers/writers |
| private ReadWriteMonitor access = new ReadWriteMonitor(); |
| |
| // deltas not broadcasted yet. Deltas are kept organized by bundle name (fragments go with their host) |
| private transient Map deltas = new HashMap(11); |
| |
| //file manager associated with the registry |
| private FileManager currentFileManager = null; |
| |
| // all registry change listeners |
| private transient ListenerList listeners = new ListenerList(); |
| |
| private RegistryObjectManager registryObjects = null; |
| |
| RegistryObjectManager getObjectManager() { |
| return registryObjects; |
| } |
| |
| /** |
| * Adds and resolves all extensions and extension points provided by the |
| * plug-in. |
| * <p> |
| * A corresponding IRegistryChangeEvent will be broadcast to all listeners |
| * interested on changes in the given plug-in. |
| * </p> |
| */ |
| public void add(Contribution element) { |
| access.enterWrite(); |
| try { |
| basicAdd(element, true); |
| fireRegistryChangeEvent(); |
| } finally { |
| access.exitWrite(); |
| } |
| } |
| |
| public void add(Contribution[] elements) { |
| access.enterWrite(); |
| try { |
| for (int i = 0; i < elements.length; i++) |
| basicAdd(elements[i], true); |
| fireRegistryChangeEvent(); |
| } finally { |
| access.exitWrite(); |
| } |
| } |
| |
| /* Utility method to help with array concatenations */ |
| static Object concatArrays(Object a, Object b) { |
| Object[] result = (Object[]) Array.newInstance(a.getClass().getComponentType(), Array.getLength(a) + Array.getLength(b)); |
| System.arraycopy(a, 0, result, 0, Array.getLength(a)); |
| System.arraycopy(b, 0, result, Array.getLength(a), Array.getLength(b)); |
| return result; |
| } |
| |
| private String addExtension(int extension) { |
| Extension addedExtension = (Extension) registryObjects.getObject(extension, RegistryObjectManager.EXTENSION); |
| String extensionPointToAddTo = addedExtension.getExtensionPointIdentifier(); |
| ExtensionPoint extPoint = registryObjects.getExtensionPointObject(extensionPointToAddTo); |
| //orphan extension |
| if (extPoint == null) { |
| registryObjects.addOrphan(extensionPointToAddTo, extension); |
| return null; |
| } |
| // otherwise, link them |
| int[] newExtensions; |
| int[] existingExtensions = extPoint.getRawChildren(); |
| newExtensions = new int[existingExtensions.length + 1]; |
| System.arraycopy(existingExtensions, 0, newExtensions, 0, existingExtensions.length); |
| newExtensions[newExtensions.length - 1] = extension; |
| link(extPoint, newExtensions); |
| return recordChange(extPoint, extension, IExtensionDelta.ADDED); |
| } |
| |
| /** |
| * Looks for existing orphan extensions to connect to the given extension |
| * point. If none is found, there is nothing to do. Otherwise, link them. |
| */ |
| private String addExtensionPoint(int extPoint) { |
| ExtensionPoint extensionPoint = (ExtensionPoint) registryObjects.getObject(extPoint, RegistryObjectManager.EXTENSION_POINT); |
| int[] orphans = registryObjects.removeOrphans(extensionPoint.getUniqueIdentifier()); |
| if (orphans == null) |
| return null; |
| link(extensionPoint, orphans); |
| return recordChange(extensionPoint, orphans, IExtensionDelta.ADDED); |
| } |
| |
| private Set addExtensionsAndExtensionPoints(Contribution element) { |
| // now add and resolve extensions and extension points |
| Set affectedNamespaces = new HashSet(); |
| int[] extPoints = element.getExtensionPoints(); |
| for (int i = 0; i < extPoints.length; i++) { |
| String namespace = this.addExtensionPoint(extPoints[i]); |
| if (namespace != null) |
| affectedNamespaces.add(namespace); |
| } |
| int[] extensions = element.getExtensions(); |
| for (int i = 0; i < extensions.length; i++) { |
| String namespace = this.addExtension(extensions[i]); |
| if (namespace != null) |
| affectedNamespaces.add(namespace); |
| } |
| return affectedNamespaces; |
| } |
| |
| public void addRegistryChangeListener(IRegistryChangeListener listener) { |
| // this is just a convenience API - no need to do any sync'ing here |
| addRegistryChangeListener(listener, null); |
| } |
| |
| public void addRegistryChangeListener(IRegistryChangeListener listener, String filter) { |
| synchronized (listeners) { |
| listeners.add(new ListenerInfo(listener, filter)); |
| } |
| } |
| |
| private void basicAdd(Contribution element, boolean link) { |
| // ignore anonymous namespaces |
| if (element.getNamespace() == null) |
| return; |
| |
| registryObjects.addContribution(element); |
| if (!link) |
| return; |
| |
| Set affectedNamespaces = addExtensionsAndExtensionPoints(element); |
| setObjectManagers(affectedNamespaces, registryObjects.createDelegatingObjectManager(registryObjects.getAssociatedObjects(element.getContributingBundle().getBundleId()))); |
| } |
| |
| private void setObjectManagers(Set affectedNamespaces, IObjectManager manager) { |
| for (Iterator iter = affectedNamespaces.iterator(); iter.hasNext();) { |
| getDelta((String) iter.next()).setObjectManager(manager); |
| } |
| } |
| |
| private void basicRemove(long bundleId) { |
| // ignore anonymous namespaces |
| Set affectedNamespaces = removeExtensionsAndExtensionPoints(bundleId); |
| Map associatedObjects = registryObjects.getAssociatedObjects(bundleId); |
| registryObjects.removeObjects(associatedObjects); |
| setObjectManagers(affectedNamespaces, registryObjects.createDelegatingObjectManager(associatedObjects)); |
| |
| registryObjects.removeContribution(bundleId); |
| } |
| |
| // allow other objects in the registry to use the same lock |
| void enterRead() { |
| access.enterRead(); |
| } |
| |
| // allow other objects in the registry to use the same lock |
| void exitRead() { |
| access.exitRead(); |
| } |
| |
| /** |
| * Broadcasts (asynchronously) the event to all interested parties. |
| */ |
| private void fireRegistryChangeEvent() { |
| // if there is nothing to say, just bail out |
| if (deltas.isEmpty() || listeners.isEmpty()) |
| return; |
| // for thread safety, create tmp collections |
| Object[] tmpListeners = listeners.getListeners(); |
| Map tmpDeltas = new HashMap(this.deltas); |
| // the deltas have been saved for notification - we can clear them now |
| deltas.clear(); |
| // do the notification asynchronously |
| new ExtensionEventDispatcherJob(tmpListeners, tmpDeltas).schedule(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getConfigurationElementsFor(java.lang.String) |
| */ |
| public IConfigurationElement[] getConfigurationElementsFor(String extensionPointId) { |
| // this is just a convenience API - no need to do any sync'ing here |
| int lastdot = extensionPointId.lastIndexOf('.'); |
| if (lastdot == -1) |
| return new IConfigurationElement[0]; |
| return getConfigurationElementsFor(extensionPointId.substring(0, lastdot), extensionPointId.substring(lastdot + 1)); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getConfigurationElementsFor(java.lang.String, java.lang.String) |
| */ |
| public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String extensionPointSimpleId) { |
| // this is just a convenience API - no need to do any sync'ing here |
| IExtensionPoint extPoint = this.getExtensionPoint(pluginId, extensionPointSimpleId); |
| if (extPoint == null) |
| return new IConfigurationElement[0]; |
| return extPoint.getConfigurationElements(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getConfigurationElementsFor(java.lang.String, java.lang.String, java.lang.String) |
| */ |
| public IConfigurationElement[] getConfigurationElementsFor(String pluginId, String extensionPointName, String extensionId) { |
| // this is just a convenience API - no need to do any sync'ing here |
| IExtension extension = this.getExtension(pluginId, extensionPointName, extensionId); |
| if (extension == null) |
| return new IConfigurationElement[0]; |
| return extension.getConfigurationElements(); |
| } |
| |
| private RegistryDelta getDelta(String namespace) { |
| // is there a delta for the plug-in? |
| RegistryDelta existingDelta = (RegistryDelta) deltas.get(namespace); |
| if (existingDelta != null) |
| return existingDelta; |
| |
| //if not, create one |
| RegistryDelta delta = new RegistryDelta(); |
| deltas.put(namespace, delta); |
| return delta; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtension(java.lang.String) |
| */ |
| public IExtension getExtension(String extensionId) { |
| if (extensionId == null) |
| return null; |
| int lastdot = extensionId.lastIndexOf('.'); |
| if (lastdot == -1) |
| return null; |
| String namespace = extensionId.substring(0, lastdot); |
| |
| Bundle[] allBundles = findAllBundles(namespace); |
| for (int i = 0; i < allBundles.length; i++) { |
| int[] extensions = registryObjects.getExtensionsFrom(allBundles[i].getBundleId()); |
| for (int j = 0; j < extensions.length; j++) { |
| Extension ext = (Extension) registryObjects.getObject(extensions[j], RegistryObjectManager.EXTENSION); |
| if (extensionId.equals(ext.getUniqueIdentifier()) && registryObjects.getExtensionPointObject(ext.getExtensionPointIdentifier()) != null) { |
| return (IExtension) registryObjects.getHandle(extensions[j], RegistryObjectManager.EXTENSION); |
| } |
| } |
| |
| } |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtension(java.lang.String, java.lang.String) |
| */ |
| public IExtension getExtension(String extensionPointId, String extensionId) { |
| // this is just a convenience API - no need to do any sync'ing here |
| int lastdot = extensionPointId.lastIndexOf('.'); |
| if (lastdot == -1) |
| return null; |
| return getExtension(extensionPointId.substring(0, lastdot), extensionPointId.substring(lastdot + 1), extensionId); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtension(java.lang.String, java.lang.String, java.lang.String) |
| */ |
| public IExtension getExtension(String pluginId, String extensionPointName, String extensionId) { |
| // this is just a convenience API - no need to do any sync'ing here |
| IExtensionPoint extPoint = getExtensionPoint(pluginId, extensionPointName); |
| if (extPoint != null) |
| return extPoint.getExtension(extensionId); |
| return null; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoint(java.lang.String) |
| */ |
| public IExtensionPoint getExtensionPoint(String xptUniqueId) { |
| return registryObjects.getExtensionPointHandle(xptUniqueId); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoint(java.lang.String, java.lang.String) |
| */ |
| public IExtensionPoint getExtensionPoint(String elementName, String xpt) { |
| access.enterRead(); |
| try { |
| return registryObjects.getExtensionPointHandle(elementName + '.' + xpt); |
| } finally { |
| access.exitRead(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoints() |
| */ |
| public IExtensionPoint[] getExtensionPoints() { |
| access.enterRead(); |
| try { |
| return registryObjects.getExtensionPointsHandles(); |
| } finally { |
| access.exitRead(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoints(java.lang.String) |
| */ |
| public IExtensionPoint[] getExtensionPoints(String namespace) { |
| access.enterRead(); |
| try { |
| Bundle[] correspondingBundles = findAllBundles(namespace); |
| IExtensionPoint[] result = ExtensionPointHandle.EMPTY_ARRAY; |
| for (int i = 0; i < correspondingBundles.length; i++) { |
| result = (IExtensionPoint[]) concatArrays(result, registryObjects.getHandles(registryObjects.getExtensionPointsFrom(correspondingBundles[i].getBundleId()), RegistryObjectManager.EXTENSION_POINT)); |
| } |
| return result; |
| } finally { |
| access.exitRead(); |
| } |
| } |
| |
| //Return all the bundles that contributes to the given namespace |
| private Bundle[] findAllBundles(String namespace) { |
| Bundle correspondingHost = Platform.getBundle(namespace); |
| if (correspondingHost == null) |
| return new Bundle[0]; |
| Bundle[] fragments = Platform.getFragments(correspondingHost); |
| if(fragments==null) |
| return new Bundle[] { correspondingHost }; |
| Bundle[] result = new Bundle[fragments.length + 1]; |
| System.arraycopy(fragments, 0, result, 0, fragments.length); |
| result[fragments.length] = correspondingHost; |
| return result; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getExtensions(java.lang.String) |
| */ |
| public IExtension[] getExtensions(String namespace) { |
| access.enterRead(); |
| try { |
| Bundle[] correspondingBundles = findAllBundles(namespace); |
| List tmp = new ArrayList(); |
| for (int i = 0; i < correspondingBundles.length; i++) { |
| Extension[] exts = (Extension[]) registryObjects.getObjects(registryObjects.getExtensionsFrom(correspondingBundles[i].getBundleId()), RegistryObjectManager.EXTENSION); |
| for (int j = 0; j < exts.length; j++) { |
| if (registryObjects.getExtensionPointObject(exts[j].getExtensionPointIdentifier()) != null) |
| tmp.add(registryObjects.getHandle(exts[j].getObjectId(), RegistryObjectManager.EXTENSION)); |
| } |
| } |
| if (tmp.size() == 0) |
| return ExtensionHandle.EMPTY_ARRAY; |
| IExtension[] result = new IExtension[tmp.size()]; |
| return (IExtension[]) tmp.toArray(result); |
| } finally { |
| access.exitRead(); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * @see org.eclipse.core.runtime.IExtensionRegistry#getNamespaces() |
| */ |
| public String[] getNamespaces() { |
| access.enterRead(); |
| try { |
| Set namespaces = registryObjects.getNamespaces(); |
| String[] result = new String[namespaces.size()]; |
| return (String[]) namespaces.toArray(result); |
| } finally { |
| access.exitRead(); |
| } |
| } |
| |
| boolean hasNamespace(long name) { |
| access.enterRead(); |
| try { |
| return registryObjects.hasContribution(name); |
| } finally { |
| access.exitRead(); |
| } |
| } |
| |
| private void link(ExtensionPoint extPoint, int[] extensions) { |
| extPoint.setRawChildren(extensions); |
| registryObjects.add(extPoint, true); |
| } |
| |
| /* |
| * Records an extension addition/removal. |
| */ |
| private String recordChange(ExtensionPoint extPoint, int extension, int kind) { |
| // avoid computing deltas when there are no listeners |
| if (listeners.isEmpty()) |
| return null; |
| ExtensionDelta extensionDelta = new ExtensionDelta(); |
| extensionDelta.setExtension(extension); |
| extensionDelta.setExtensionPoint(extPoint.getObjectId()); |
| extensionDelta.setKind(kind); |
| getDelta(extPoint.getNamespace()).addExtensionDelta(extensionDelta); |
| return extPoint.getNamespace(); |
| } |
| |
| /* |
| * Records a set of extension additions/removals. |
| */ |
| private String recordChange(ExtensionPoint extPoint, int[] extensions, int kind) { |
| if (listeners.isEmpty()) |
| return null; |
| if (extensions == null || extensions.length == 0) |
| return null; |
| RegistryDelta pluginDelta = getDelta(extPoint.getNamespace()); |
| for (int i = 0; i < extensions.length; i++) { |
| ExtensionDelta extensionDelta = new ExtensionDelta(); |
| extensionDelta.setExtension(extensions[i]); |
| extensionDelta.setExtensionPoint(extPoint.getObjectId()); |
| extensionDelta.setKind(kind); |
| pluginDelta.addExtensionDelta(extensionDelta); |
| } |
| return extPoint.getNamespace(); |
| } |
| |
| // private void recordRemoval(long removedBundleId) { |
| // int[] exts = registryObjects.getExtensionsFrom(removedBundleId); |
| // Extension[] aexts = (Extension[]) registryObjects.getObjects(exts, RegistryObjectManager.EXTENSION); |
| // IObjectManager mgr = registryObjects.getRemovedObjects(removedBundleId); |
| // for (int i = 0; i < aexts.length; i++) { |
| // getDelta(registryObjects.getExtensionPointObject(aexts[i].getExtensionPointIdentifier()).getNamespace()).setObjectManager(mgr); |
| // } |
| // } |
| |
| /** |
| * Unresolves and removes all extensions and extension points provided by |
| * the plug-in. |
| * <p> |
| * A corresponding IRegistryChangeEvent will be broadcast to all listeners |
| * interested on changes in the given plug-in. |
| * </p> |
| */ |
| public void remove(long removedBundleId) { |
| access.enterWrite(); |
| try { |
| basicRemove(removedBundleId); |
| fireRegistryChangeEvent(); |
| } finally { |
| access.exitWrite(); |
| } |
| } |
| |
| //Return the affected namespace |
| private String removeExtension(int extensionId) { |
| Extension extension = (Extension) registryObjects.getObject(extensionId, RegistryObjectManager.EXTENSION); |
| String xptName = extension.getExtensionPointIdentifier(); |
| ExtensionPoint extPoint = registryObjects.getExtensionPointObject(xptName); |
| if (extPoint == null) { |
| registryObjects.removeOrphan(xptName, extensionId); |
| return null; |
| } |
| // otherwise, unlink the extension from the extension point |
| int[] existingExtensions = extPoint.getRawChildren(); |
| int[] newExtensions = RegistryObjectManager.EMPTY_INT_ARRAY; |
| if (existingExtensions.length > 1) { |
| if (existingExtensions.length == 1) |
| newExtensions = RegistryObjectManager.EMPTY_INT_ARRAY; |
| |
| newExtensions = new int[existingExtensions.length - 1]; |
| for (int i = 0, j = 0; i < existingExtensions.length; i++) |
| if (existingExtensions[i] != extension.getObjectId()) |
| newExtensions[j++] = existingExtensions[i]; |
| } |
| link(extPoint, newExtensions); |
| return recordChange(extPoint, extension.getObjectId(), IExtensionDelta.REMOVED); |
| } |
| |
| private String removeExtensionPoint(int extPoint) { |
| ExtensionPoint extensionPoint = (ExtensionPoint) registryObjects.getObject(extPoint, RegistryObjectManager.EXTENSION_POINT); |
| int[] existingExtensions = extensionPoint.getRawChildren(); |
| if (existingExtensions == null || existingExtensions.length == 0) { |
| return null; |
| } |
| //Remove the extension point from the registry object |
| registryObjects.addOrphans(extensionPoint.getUniqueIdentifier(), existingExtensions); |
| link(extensionPoint, RegistryObjectManager.EMPTY_INT_ARRAY); |
| return recordChange(extensionPoint, existingExtensions, IExtensionDelta.REMOVED); |
| } |
| |
| private Set removeExtensionsAndExtensionPoints(long bundleId) { |
| Set affectedNamespaces = new HashSet(); |
| int[] extensions = registryObjects.getExtensionsFrom(bundleId); |
| for (int i = 0; i < extensions.length; i++) { |
| String namespace = this.removeExtension(extensions[i]); |
| if (namespace != null) |
| affectedNamespaces.add(namespace); |
| } |
| |
| // remove extension points |
| int[] extPoints = registryObjects.getExtensionPointsFrom(bundleId); |
| for (int i = 0; i < extPoints.length; i++) { |
| String namespace = this.removeExtensionPoint(extPoints[i]); |
| if (namespace != null) |
| affectedNamespaces.add(namespace); |
| } |
| return affectedNamespaces; |
| } |
| |
| public void removeRegistryChangeListener(IRegistryChangeListener listener) { |
| synchronized (listeners) { |
| listeners.remove(new ListenerInfo(listener, null)); |
| } |
| } |
| |
| public ExtensionRegistry() { |
| boolean fromCache = false; |
| registryObjects = new RegistryObjectManager(); |
| if (!"true".equals(System.getProperty(InternalPlatform.PROP_NO_REGISTRY_CACHE))) { //$NON-NLS-1$ |
| // Try to read the registry from the cache first. If that fails, create a new registry |
| long start = 0; |
| if (InternalPlatform.DEBUG) |
| start = System.currentTimeMillis(); |
| |
| //Find the cache in the local configuration area |
| File cacheFile = null; |
| try { |
| currentFileManager = InternalPlatform.getDefault().getRuntimeFileManager(); |
| cacheFile = currentFileManager.lookup(TableReader.TABLE, false); |
| } catch (IOException e) { |
| //Ignore the exception. The registry will be rebuilt from the xml files. |
| } |
| //Find the cache in the shared configuration area |
| if (cacheFile == null || !cacheFile.isFile()) { |
| Location currentLocation = Platform.getConfigurationLocation(); |
| Location parentLocation = null; |
| if (currentLocation != null && (parentLocation = currentLocation.getParentLocation()) != null) { |
| try { |
| currentFileManager = new FileManager(new File(parentLocation.getURL().getFile() + '/' + Platform.PI_RUNTIME), parentLocation.isReadOnly() ? "none" : null); //$NON-NLS-1$ |
| currentFileManager.open(false); |
| cacheFile = currentFileManager.lookup(TableReader.TABLE, false); |
| } catch (IOException e) { |
| //Ignore the exception. The registry will be rebuilt from the xml files. |
| } |
| } |
| } |
| |
| //The cache is made of several files, find the real names of these other files. If all files are found, try to initialize the objectManager |
| if (cacheFile != null && cacheFile.isFile()) { |
| TableReader.setTableFile(cacheFile); |
| try { |
| TableReader.setExtraDataFile(currentFileManager.lookup(TableReader.EXTRA, false)); |
| TableReader.setMainDataFile(currentFileManager.lookup(TableReader.MAIN, false)); |
| TableReader.setContributionsFile(currentFileManager.lookup(TableReader.CONTRIBUTIONS, false)); |
| TableReader.setOrphansFile(currentFileManager.lookup(TableReader.ORPHANS, false)); |
| fromCache = registryObjects.init(computeRegistryStamp()); |
| } catch (IOException e) { |
| // Ignore the exception. The registry will be rebuilt from the xml files. |
| } |
| } |
| |
| if (InternalPlatform.DEBUG && fromCache) |
| System.out.println("Reading registry cache: " + (System.currentTimeMillis() - start)); //$NON-NLS-1$ |
| |
| if (InternalPlatform.DEBUG_REGISTRY) { |
| if (!fromCache) |
| System.out.println("Reloading registry from manifest files..."); //$NON-NLS-1$ |
| else |
| System.out.println("Using registry cache..."); //$NON-NLS-1$ |
| } |
| } |
| |
| String debugOption = InternalPlatform.getDefault().getOption(OPTION_DEBUG_EVENTS_EXTENSION); |
| DEBUG = debugOption == null ? false : debugOption.equalsIgnoreCase("true"); //$NON-NLS-1$ |
| if (DEBUG) |
| addRegistryChangeListener(new IRegistryChangeListener() { |
| public void registryChanged(IRegistryChangeEvent event) { |
| System.out.println(event); |
| } |
| }); |
| |
| // register a listener to catch new bundle installations/resolutions. |
| pluginBundleListener = new EclipseBundleListener(this); |
| InternalPlatform.getDefault().getBundleContext().addBundleListener(pluginBundleListener); |
| |
| // populate the registry with all the currently installed bundles. |
| // There is a small window here while processBundles is being |
| // called where the pluginBundleListener may receive a BundleEvent |
| // to add/remove a bundle from the registry. This is ok since |
| // the registry is a synchronized object and will not add the |
| // same bundle twice. |
| if (!fromCache) |
| pluginBundleListener.processBundles(InternalPlatform.getDefault().getBundleContext().getBundles()); |
| |
| InternalPlatform.getDefault().getBundleContext().registerService(IExtensionRegistry.class.getName(), this, new Hashtable()); //$NON-NLS-1$ |
| |
| } |
| |
| public void stop() { |
| InternalPlatform.getDefault().getBundleContext().removeBundleListener(this.pluginBundleListener); |
| if (!registryObjects.isDirty()) |
| return; |
| FileManager manager = InternalPlatform.getDefault().getRuntimeFileManager(); |
| File tableFile = null; |
| File mainFile = null; |
| File extraFile = null; |
| File contributionsFile = null; |
| File orphansFile = null; |
| try { |
| manager.lookup(TableReader.TABLE, true); |
| manager.lookup(TableReader.MAIN, true); |
| manager.lookup(TableReader.EXTRA, true); |
| manager.lookup(TableReader.CONTRIBUTIONS, true); |
| manager.lookup(TableReader.ORPHANS, true); |
| tableFile = File.createTempFile(TableReader.TABLE, ".new", manager.getBase()); //$NON-NLS-1$ |
| mainFile = File.createTempFile(TableReader.MAIN, ".new", manager.getBase()); //$NON-NLS-1$ |
| extraFile = File.createTempFile(TableReader.EXTRA, ".new", manager.getBase()); //$NON-NLS-1$ |
| contributionsFile = File.createTempFile(TableReader.CONTRIBUTIONS, ".new", manager.getBase()); //$NON-NLS-1$ |
| orphansFile = File.createTempFile(TableReader.ORPHANS, ".new", manager.getBase()); //$NON-NLS-1$ |
| TableWriter.setTableFile(tableFile); |
| TableWriter.setExtraDataFile(extraFile); |
| TableWriter.setMainDataFile(mainFile); |
| TableWriter.setContributionsFile(contributionsFile); |
| TableWriter.setOrphansFile(orphansFile); |
| } catch (IOException e) { |
| return; //Ignore the exception since we can recompute the cache |
| } |
| try { |
| if (new TableWriter().saveCache(registryObjects, computeRegistryStamp())) |
| manager.update(new String[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.ORPHANS}, new String[] {tableFile.getName(), mainFile.getName(), extraFile.getName(), contributionsFile.getName(), orphansFile.getName()}); |
| } catch (IOException e) { |
| //Ignore the exception since we can recompute the cache |
| } |
| if (currentFileManager != InternalPlatform.getDefault().getRuntimeFileManager()) |
| currentFileManager.close(); |
| } |
| |
| private long computeRegistryStamp() { |
| // If the check config prop is false or not set then exit |
| if (!"true".equalsIgnoreCase(System.getProperty(InternalPlatform.PROP_CHECK_CONFIG))) //$NON-NLS-1$ |
| return 0; |
| Bundle[] allBundles = InternalPlatform.getDefault().getBundleContext().getBundles(); |
| long result = 0; |
| for (int i = 0; i < allBundles.length; i++) { |
| URL pluginManifest = allBundles[i].getEntry("plugin.xml"); //$NON-NLS-1$ |
| if (pluginManifest == null) |
| pluginManifest = allBundles[i].getEntry("fragment.xml"); //$NON-NLS-1$ |
| if (pluginManifest == null) |
| continue; |
| try { |
| URLConnection connection = pluginManifest.openConnection(); |
| result ^= connection.getLastModified() + allBundles[i].getBundleId(); |
| } catch (IOException e) { |
| return 0; |
| } |
| } |
| return result; |
| } |
| } |