From fdf4ae81c01c37857f9f915106f1a75586e17304 Mon Sep 17 00:00:00 2001 From: Pascal Rapicault Date: Thu, 16 Feb 2006 20:29:01 +0000 Subject: Bug 127783 - Clean up RegistryStrategy from the org.eclipse.equinox.registry --- .../core/internal/registry/ExtensionRegistry.java | 48 +++----- .../core/internal/registry/osgi/Activator.java | 23 +++- .../registry/osgi/EquinoxRegistryStrategy.java | 78 ++++++++----- .../registry/osgi/RegistryStrategyOSGI.java | 75 +++--------- .../org/eclipse/core/runtime/RegistryFactory.java | 7 +- .../runtime/dynamichelpers/ExtensionTracker.java | 2 +- .../eclipse/core/runtime/spi/RegistryStrategy.java | 126 +++++++++++++-------- 7 files changed, 186 insertions(+), 173 deletions(-) diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java index 0dbf750b4..91eba625c 100644 --- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java +++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/ExtensionRegistry.java @@ -541,10 +541,7 @@ public class ExtensionRegistry implements IExtensionRegistry { if (registryStrategy != null) strategy = registryStrategy; else - strategy = new RegistryStrategy(null, true); - - // create the file manager right away - setFileManager(strategy.getStorage(), strategy.isCacheReadOnly()); + strategy = new RegistryStrategy(null, null); this.masterToken = masterToken; this.userToken = userToken; @@ -725,39 +722,30 @@ public class ExtensionRegistry implements IExtensionRegistry { } public long computeState() { - return strategy.cacheComputeState(); + return strategy.getContainerTimestamp(); } public long computeTimeStamp() { - return strategy.cacheComputeTimeStamp(); + return strategy.getContributionsTimestamp(); } - // Check that cache is actually present in the specified location + // Find the first location that contains a cache table file and set file manager to it. protected boolean checkCache() { - File cacheFile = null; - if (cacheStorageManager != null) { - try { - cacheFile = cacheStorageManager.lookup(TableReader.getTestFileName(), false); - } catch (IOException e) { - //Ignore the exception. The registry will be rebuilt from the xml files. - } - } - if (cacheFile != null && cacheFile.isFile()) - return true; // primary location is fine - - // check alternative cache location if available - File alternativeBase = strategy.cacheAlternativeLocation(); - if (alternativeBase != null) { - setFileManager(alternativeBase, true); + for (int index = 0; index < strategy.getLocationsLength(); index++) { + File possibleCacheLocation = strategy.getStorage(index); + if (possibleCacheLocation == null) + break; // bail out on the first null + setFileManager(possibleCacheLocation, strategy.isCacheReadOnly(index)); if (cacheStorageManager != null) { // check this new location: - cacheFile = null; + File cacheFile = null; try { cacheFile = cacheStorageManager.lookup(TableReader.getTestFileName(), false); } catch (IOException e) { //Ignore the exception. The registry will be rebuilt from the xml files. } - return (cacheFile != null && cacheFile.isFile()); + if (cacheFile != null && cacheFile.isFile()) + return true; // found the appropriate location } } return false; @@ -854,17 +842,14 @@ public class ExtensionRegistry implements IExtensionRegistry { /** * Access check for add/remove operations: - * a) for modifiable registry key is not required (null is fine) - * b) for non-modifiable registry master key allows all operations - * c) for non-modifiable registry user key allows modifications of non-persisted elements + * - Master key allows all operations + * - User key allows modifications of non-persisted elements * * @param key key to the registry supplied by the user * @param persist true if operation affects persisted elements * @return true is the key grants read/write access to the registry */ private boolean checkReadWriteAccess(Object key, boolean persist) { - if (strategy.isModifiable()) - return true; if (masterToken == key) return true; if (userToken == key && !persist) @@ -880,7 +865,7 @@ public class ExtensionRegistry implements IExtensionRegistry { RegistryContributor internalContributor = (RegistryContributor) contributor; registryObjects.addContributor(internalContributor); // only adds a contributor if it is not already present - + String ownerName = internalContributor.getActualName(); String message = NLS.bind(RegistryMessages.parse_problems, ownerName); MultiStatus problems = new MultiStatus(RegistryMessages.OWNER_NAME, ExtensionsParser.PARSE_PROBLEM, message, null); @@ -924,8 +909,6 @@ public class ExtensionRegistry implements IExtensionRegistry { * If the registry is not modifiable, this method is an access controlled method. * Proper token should be passed as an argument for non-modifiable registries. *
- * @see org.eclipse.core.runtime.spi.RegistryStrategy#isModifiable() - * * @param identifier Id of the extension point. If non-qualified names is supplied, * it will be converted internally into a fully qualified name * @param contributor the contributor of this extension point @@ -998,7 +981,6 @@ public class ExtensionRegistry implements IExtensionRegistry { * If the registry is not modifiable, this method is an access controlled method. * Proper token should be passed as an argument for non-modifiable registries. * - * @see org.eclipse.core.runtime.spi.RegistryStrategy#isModifiable() * @see org.eclipse.core.internal.registry.spi.ConfigurationElementDescription * * @param identifier Id of the extension. If non-qualified name is supplied, diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java index 0fea3b049..f183ff9ad 100644 --- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java +++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/Activator.java @@ -102,9 +102,28 @@ public class Activator implements BundleActivator { if ("true".equals(bundleContext.getProperty(IRegistryConstants.PROP_REGISTRY_NULL_USER_TOKEN))) //$NON-NLS-1$ userRegistryKey = null; + // Determine primary and alternative registry locations. Eclipse extension registry cache + // can be found in one of the two locations: + // a) in the local configuration area (standard location passed in by the platform) -> priority + // b) in the shared configuration area (typically, shared install is used) + File[] registryLocations; + boolean[] readOnlyLocations; + Location configuration = OSGIUtils.getDefault().getConfigurationLocation(); - File theStorageDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR); - EquinoxRegistryStrategy registryStrategy = new EquinoxRegistryStrategy(theStorageDir, configuration.isReadOnly(), masterRegistryKey); + File primaryDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR); + boolean primaryReadOnly = configuration.isReadOnly(); + + Location parentLocation = configuration.getParentLocation(); + if (parentLocation != null) { + File secondaryDir = new File(parentLocation.getURL().getFile() + '/' + IRegistryConstants.RUNTIME_NAME); + registryLocations = new File[] {primaryDir, secondaryDir}; + readOnlyLocations = new boolean[] {primaryReadOnly, true}; // secondary Eclipse location is always read only + } else { + registryLocations = new File[] {primaryDir}; + readOnlyLocations = new boolean[] {primaryReadOnly}; + } + + EquinoxRegistryStrategy registryStrategy = new EquinoxRegistryStrategy(registryLocations, readOnlyLocations, masterRegistryKey); defaultRegistry = RegistryFactory.createRegistry(registryStrategy, masterRegistryKey, userRegistryKey); registryRegistration = Activator.getContext().registerService(IExtensionRegistry.class.getName(), defaultRegistry, new Hashtable()); diff --git a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EquinoxRegistryStrategy.java b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EquinoxRegistryStrategy.java index 907f88c70..26968a69a 100644 --- a/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EquinoxRegistryStrategy.java +++ b/bundles/org.eclipse.equinox.registry/src/org/eclipse/core/internal/registry/osgi/EquinoxRegistryStrategy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005 IBM Corporation and others. + * Copyright (c) 2005, 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 @@ -11,18 +11,23 @@ package org.eclipse.core.internal.registry.osgi; import java.io.File; -import org.eclipse.core.internal.registry.IRegistryConstants; +import java.util.Map; import org.eclipse.core.internal.runtime.RuntimeLog; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.spi.RegistryStrategy; import org.eclipse.osgi.service.resolver.PlatformAdmin; /** - * The registry strategy used by the Equinox extension registry. Adds to the OSGi registry: - * - Use debug information supplied via .options files - * - Use Eclipse logging - * - Use Eclipse platform state for cache validation - * - Supplied alternative cache location (primarily used with shared installs) + * The registry strategy used by the Equinox extension registry. Adds to the + * OSGi registry: + *+ * Locations in the list will be checked sequentially (starting with index 0) + * until cache files are found. The first location containing cache files will + * be used. It will be assigned the "read only" attribute specified in the + * corresponding slot of the cacheReadOnly array. + *
+ *+ * The arrays of the storage files (theStorageDir) and read only flags (cacheReadOnly) + * must be same size. + *
+ * @param theStorageDir - array of file system directories to store cache files; might be null + * @param cacheReadOnly - array of read only attributes. True: cache at this location is read + * only; false: cache is read/write */ - public RegistryStrategy(File theStorageDir, boolean cacheReadOnly) { + public RegistryStrategy(File[] theStorageDir, boolean[] cacheReadOnly) { this.theStorageDir = theStorageDir; this.cacheReadOnly = cacheReadOnly; } - public final File getStorage() { - return theStorageDir; + /** + * Returns number of possible cache locations for this registry + * @return number of possible cache locations for this registry + */ + public final int getLocationsLength() { + if (theStorageDir == null) + return 0; + return theStorageDir.length; } - public final boolean isCacheReadOnly() { - return cacheReadOnly; + /** + * Returns the possible registry cache location identified by the index. + * Locations with lower index have higher priority and are considered first. + * + * @param index index of the possible registry location + * @return potential registry cache location + */ + public final File getStorage(int index) { + if (theStorageDir != null) + return theStorageDir[index]; + return null; } /** - * Specifies if registry clients can add information into the registry. - * @return true: clients can add information; false: proper token should be supplied - * in order to add information into the registry. + * Returns read only status of the registry cache location. + * @param index index of the possible registry location + * @return true: location is read only; false: location is read/write */ - public boolean isModifiable() { + public final boolean isCacheReadOnly(int index) { + if (cacheReadOnly != null) + return cacheReadOnly[index]; return true; } @@ -184,8 +211,7 @@ public class RegistryStrategy { * @param registry - the extension registry (NOT thread safe) */ public void scheduleChangeEvent(Object[] listeners, Map deltas, Object registry) { - if (registry instanceof ExtensionRegistry) - ((ExtensionRegistry) registry).scheduleChangeEvent(listeners, deltas); + ((ExtensionRegistry) registry).scheduleChangeEvent(listeners, deltas); } /** @@ -256,52 +282,58 @@ public class RegistryStrategy { /** * This method is called as a part of the registry cache validation. The cache is valid - * on the registry startup if the pair {state, time stamp} supplied by the application - * is the same as the {state, time stamp} saved in the registry cache. - * - * This method produces a number that corresponds to the current state of the data stored - * in the registry. Increment the state if registry content changed and the registry cache - * is no longer valid. - * + * on the registry startup if the pair {container time stamp, contributors time stamp} + * supplied by the registry strategy is the same as the {container time stamp, contributors time stamp} + * stored in the registry cache. The goal of this method is to be able to catch modifications + * made to the original data contributed into the registry and not reflected in the registry cache. + *+ * The method produces a number that corresponds to the current state of the data stored + * by the container. Increment the stamp if the data stored in the container has been updated + * so that the data cached by the registry is no longer valid. + *
+ * For instance, in Eclipse addition or removal of a bundle results in the number returned by + * this method being incremented. As a result, if a bundle that contributed plugin.xml into + * the extension registry was modified, the state doesn't match the state stored in the registry + * cache. In this case the cache content becomes invalid and registry needs to be re-created from + * the original data. + *
+ * Generally, treat this number as a hash code for the data stored in the registry. + * It stays the same as long as the registry content is not changing. It becomes a different + * number as the registry content gets modified. + *
* Return 0 to indicate that state verification is not required. * * @return number indicating state of the application data */ - public long cacheComputeState() { + public long getContainerTimestamp() { return 0; } /** * This method is called as a part of the registry cache validation. The cache is valid - * on the registry startup if the pair {state, time stamp} supplied by the application - * is the same as the {state, time stamp} saved in the registry cache. - * - * This method calculates current time stamp for the elements stored in the extension - * registry. Treat this number as a hash code for the data stored in the registry. - * It stays the same as long as the registry content is not changing. It becomes a different - * number as the registry content gets modified. - * + * on the registry startup if the pair {container time stamp, contributors time stamp} + * supplied by the registry strategy is the same as the {container time stamp, contributors time stamp} + * stored in the registry cache. The goal of this method is to be able to catch modifications + * made to the original data contributed into the registry and not reflected in the registry cache. + *
+ * The method calculates a number describing time when the contributions cached by + * the registry were last modified. For instance, in the Eclipse registry this number is calculated + * as a function of the time when plugin.xml files have been modified. If the number is not the same + * as the number stored in the cache, it means that plugin.xml file(s) have been updated and + * the cached information is no longer valid. + *
+ * Generally, treat this number as a hash code for the time of modifications of contributions stored + * in the registry. It stays the same as long as the contributions aren't changing. It becomes + * a different number when contributions are modified. + *
* Return 0 to indicate that no time stamp verification is required. * * @return the time stamp calculated with the application data */ - public long cacheComputeTimeStamp() { + public long getContributionsTimestamp() { return 0; } - /** - * In case if the primary cache location has no data in it, the registry - * attemps to get cached information from this alternative location. The cache - * at alternative location is always considered read-only. - * - * Return null if alternative cache location is not supported. - * - * @return - directory containing the alternative cache location - */ - public File cacheAlternativeLocation() { - return null; - } - private SAXParserFactory theXMLParserFactory = null; /** -- cgit v1.2.3