KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > runtime > spi > RegistryStrategy


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.runtime.spi;
12
13 import java.io.File JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.ResourceBundle JavaDoc;
16 import javax.xml.parsers.SAXParserFactory JavaDoc;
17 import org.eclipse.core.internal.registry.*;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.osgi.util.NLS;
20
21 /**
22  * This is the basic registry strategy. It describes how the registry does logging,
23  * message translation, extra start/stop processing, event scheduling, caching,
24  * and debugging.
25  * <p>
26  * In this strategy:
27  * </p><p><ul>
28  * <li>Logging is done onto <code>System.out</code>;</li>
29  * <li>The translation routine assumes that keys are prefixed with <code>'%'/<code>;</li>
30  * <li>Caching is enabled and doesn't use state or time stamp validation;</li>
31  * <li>Standard Java class loading is used to create executable extensions.</li>
32  * </ul></p><p>
33  * This class can be used without OSGi running.
34  * </p><p>
35  * This class can be overridden and/or instantiated by clients.
36  * </p><p>
37  * <b>Note:</b> This class/interface is part of an interim API that is still under
38  * development and expected to change significantly before reaching stability.
39  * It is being made available at this early stage to solicit feedback from pioneering
40  * adopters on the understanding that any code that uses this API will almost certainly
41  * be broken (repeatedly) as the API evolves.
42  * </p>
43  * @since org.eclipse.equinox.registry 3.2
44  */

45 public class RegistryStrategy {
46
47     private SAXParserFactory JavaDoc theXMLParserFactory = null;
48
49     /**
50      * Array of file system directories to store cache files; might be <code>null</code>
51      */

52     private final File JavaDoc[] storageDirs;
53
54     /**
55      * Specifies if the registry file cache is read only; might be <code>null</code>
56      */

57     private final boolean[] cacheReadOnly;
58     
59     /**
60      * Constructor for this default registry strategy.
61      * <p>
62      * The strategy sequentially checks the array of storage directories to
63      * discover the location of the registry cache formed by previous invocations of the extension
64      * registry. Once found, the location is used to store registry cache. If this value
65      * is <code>null</code> then caching of the registry content is disabled.
66      * </p><p>
67      * The cache read-only array is an array the same length as the storage directory array.
68      * It contains boolean values indicating whether or not each storage directory is read-only.
69      * If the value at an index is <code>true</code> then the location at the corresponding index
70      * in the storage directories array is read-only; if <code>false</code> then the cache location
71      * is read-write. The array can be <code>null</code> if the <code>storageDirs</code> parameter
72      * is <code>null</code>.
73      * </p>
74      *
75      * @param storageDirs array of file system directories, or <code>null</code>
76      * @param cacheReadOnly array of read only attributes, or <code>null</code>
77      */

78     public RegistryStrategy(File JavaDoc[] storageDirs, boolean[] cacheReadOnly) {
79         this.storageDirs = storageDirs;
80         this.cacheReadOnly = cacheReadOnly;
81     }
82
83     /**
84      * Returns the number of possible cache locations for this registry.
85      *
86      * @return number of possible cache locations for this registry
87      */

88     public final int getLocationsLength() {
89         if (storageDirs == null)
90             return 0;
91         return storageDirs.length;
92     }
93
94     /**
95      * Returns the possible registry cache location identified by the index.
96      *
97      * @param index index of the possible registry location
98      * @return potential registry cache location
99      */

100     public final File JavaDoc getStorage(int index) {
101         if (storageDirs != null)
102             return storageDirs[index];
103         return null;
104     }
105
106     /**
107      * Returns the read-only status of the registry cache location.
108      *
109      * @param index the index of the possible registry location
110      * @return <code>true</code> if the location is read only and
111      * <code>false</code> if the location is read/write
112      */

113     public final boolean isCacheReadOnly(int index) {
114         if (cacheReadOnly != null)
115             return cacheReadOnly[index];
116         return true;
117     }
118
119     /**
120      * Override this method to provide customized logging functionality
121      * to the registry. The method adds a log entry based on the supplied status.
122      * <p>
123      * This method writes a message to <code>System.out</code>
124      * in the following format:
125      * <pre>
126      * [Error|Warning|Log]: Main error message
127      * [Error|Warning|Log]: Child error message 1
128      * ...
129      * [Error|Warning|Log]: Child error message N
130      * </pre></p>
131      *
132      * @param status the status to log
133      */

134     public void log(IStatus status) {
135         RegistrySupport.log(status, null);
136     }
137
138     /**
139      * Translates key using the supplied resource bundle. The resource bundle is
140      * optional and might be <code>null</code>.
141      * <p>
142      * The default translation routine assumes that keys are prefixed with '%'. If
143      * no resource bundle is present, the key itself (without leading '%') is returned.
144      * There is no decoding for the leading '%%'.
145      * </p>
146      *
147      * @param key message key to be translated
148      * @param resources resource bundle, or <code>null</code>
149      * @return the translated string, must not be <code>null</code>
150      */

151     public String JavaDoc translate(String JavaDoc key, ResourceBundle JavaDoc resources) {
152         return RegistrySupport.translate(key, resources);
153     }
154
155     /**
156      * Override this method to provide additional processing performed
157      * when the registry is created and started. Overrides should call
158      * <code>super.onStart()</code> at the beginning of the processing.
159      *
160      * @param registry the extension registry being started
161      */

162     public void onStart(IExtensionRegistry registry) {
163         // The default implementation
164
}
165
166     /**
167      * Override this method to provide additional processing to be performed
168      * just before the registry is stopped. Overrides should call
169      * <code>super.onStop()</code> at the end of the processing.
170      * @param registry the extension registry being stopped
171      */

172     public void onStop(IExtensionRegistry registry) {
173         // The default implementation
174
}
175
176     /**
177      * Creates an executable extension. Override this method to supply an alternative processing
178      * for the creation of executable extensions.
179      * <p>
180      * This method receives the contributor of the executable extension and, possibly,
181      * an optional contributor name if specified by the executable extension. The overridden
182      * contributor name might be <code>null</code>.
183      * </p><p>
184      * In this implementation registry attempts to instantiate the class specified via
185      * the class name (must not be <code>null</code>) using standard Java reflection mechanism.
186      * This method assumes that such class has a default constructor with no arguments.
187      * </p>
188      *
189      * @param contributor the contributor of this executable extension
190      * @param className the name of the class to be instantiated
191      * @param overridenContributorName the contributor to be used, or <code>null</code> if not specified
192      * @return the object created, or <code>null</code>
193      * @throws CoreException if there was a problem creating the executable extension
194      * @see IConfigurationElement#createExecutableExtension(String)
195      * @see IExecutableExtension
196      */

197     public Object JavaDoc createExecutableExtension(RegistryContributor contributor, String JavaDoc className, String JavaDoc overridenContributorName) throws CoreException {
198         Object JavaDoc result = null;
199         Class JavaDoc classInstance = null;
200         try {
201             classInstance = Class.forName(className);
202         } catch (ClassNotFoundException JavaDoc e1) {
203             String JavaDoc message = NLS.bind(RegistryMessages.exExt_findClassError, contributor.getActualName(), className);
204             throw new CoreException(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IRegistryConstants.PLUGIN_ERROR, message, e1));
205         }
206
207         try {
208             result = classInstance.newInstance();
209         } catch (Exception JavaDoc e) {
210             String JavaDoc message = NLS.bind(RegistryMessages.exExt_instantiateClassError, contributor.getActualName(), className);
211             throw new CoreException(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IRegistryConstants.PLUGIN_ERROR, message, e));
212         }
213         return result;
214     }
215
216     /**
217      * Override this method to customize scheduling of an extension registry event. Note that this method
218      * <strong>must</strong> make the following call to actually process the event:
219      * <p><pre><code>
220      * RegistryStrategy.processChangeEvent(listeners, deltas, registry);
221      * </code></pre></p><p>
222      * In the default implementation, the method registry events are executed in a queue
223      * on a separate thread (i.e. asynchronously, sequentially).
224      * </p>
225      *
226      * @param listeners the list of active listeners (thread safe); may not be <code>null</code>
227      * @param deltas the registry deltas (thread safe); may not be <code>null</code>
228      * @param registry the extension registry (NOT thread safe); may not be <code>null</code>
229      */

230     public void scheduleChangeEvent(Object JavaDoc[] listeners, Map JavaDoc deltas, Object JavaDoc registry) {
231         ((ExtensionRegistry) registry).scheduleChangeEvent(listeners, deltas);
232     }
233
234     /**
235      * This method performs actual processing of the registry change event. It should
236      * only be used by overrides of the RegistryStrategy.scheduleChangeEvent. It will
237      * return <code>null</code> if an unexpected registry type was encountered.
238      *
239      * @param listeners the list of active listeners; may not be <code>null</code>
240      * @param deltas the extension registry deltas; may not be <code>null</code>
241      * @param registry the extension registry; may not be <code>null</code>
242      * @return status of the operation or <code>null</code>
243      */

244     public final static IStatus processChangeEvent(Object JavaDoc[] listeners, Map JavaDoc deltas, Object JavaDoc registry) {
245         if (registry instanceof ExtensionRegistry)
246             return ((ExtensionRegistry) registry).processChangeEvent(listeners, deltas);
247         return null;
248     }
249
250     /**
251      * Override this method to specify debug requirements to the registry. In the default
252      * implementation this method returns <code>false</code> indicating that debug functionality
253      * is turned off.
254      * <p>
255      * Note that in a general case the extension registry plug-in doesn't depend on OSGI and
256      * therefore cannot use Eclipse .options files to discover debug options.
257      * </p>
258      *
259      * @return <code>true</code> if debug logging and validation should be performed and
260      * <code>false</code> otherwise
261      */

262     public boolean debug() {
263         return false;
264     }
265
266     /**
267      * Override this method to specify debug requirements for the registry event processing.
268      * In the default implementation this method returns <code>false</code> indicating that
269      * debug of the registry events is turned off.
270      * <p>
271      * Note that in a general case the extension registry plug-in doesn't depend on OSGI and
272      * therefore cannot use Eclipse .options files to discover debug options.
273      * </p>
274      *
275      * @return <code>true</code> if debug logging and validation of the registry events
276      * should be performed and <code>false</code> otherwise
277      */

278     public boolean debugRegistryEvents() {
279         return false;
280     }
281
282     /**
283      * Specifies if the extension registry should use cache to store registry data between
284      * invocations.
285      * <p>
286      * The default implementation enables caching returning <code>true</code>.
287      * </p>
288      *
289      * @return <code>true</code> if the cache should be used and <code>false</code> otherwise
290      */

291     public boolean cacheUse() {
292         return true;
293     }
294
295     /**
296      * Specifies if lazy cache loading is used.
297      * <p>
298      * The default implementation specifies that lazy cache loading is going to be used
299      * and therefore returns <code>true</code>.
300      * </p>
301      *
302      * @return <code>true</code> if lazy cache loading is used and <code>false</code> otherwise
303      */

304     public boolean cacheLazyLoading() {
305         return true;
306     }
307
308     /**
309      * This method is called as a part of the registry cache validation. The cache is valid
310      * on the registry startup if the pair {container time stamp, contributors time stamp}
311      * supplied by the registry strategy is the same as the {container time stamp, contributors time stamp}
312      * stored in the registry cache. The goal of the validation is to be able to catch modifications
313      * made to the original data contributed into the registry and not reflected in the registry cache.
314      * <p>
315      * The method produces a number that corresponds to the current state of the data stored
316      * by the container. Increment the stamp if the data stored in the container has been updated
317      * so that the data cached by the registry is no longer valid. For instance, in Eclipse addition
318      * or removal of a bundle results in the number returned by this method being incremented. As a result,
319      * if a bundle that contributed plugin.xml into the extension registry was modified, the state doesn't
320      * match the state stored in the registry cache. In this case the cache content becomes invalid and
321      * the registry needs to be re-created from the original data.
322      * </p><p>
323      * Generally, treat this number as a hash code for the data stored in the registry.
324      * It stays the same as long as the registry content is not changing. It becomes a different
325      * number as the registry content gets modified.
326      * </p><p>
327      * Return 0 to indicate that state verification is not required.
328      * </p>
329      *
330      * @return number indicating state of the application data
331      */

332     public long getContainerTimestamp() {
333         return 0;
334     }
335
336     /**
337      * This method is called as a part of the registry cache validation. The method calculates
338      * a number describing the time when the originating contributions (i.e., plugin.xml files
339      * in case of the Eclipse registry) were last modified.
340      * <p>
341      * The value returned by the method is compared with the timestamp tracked by the registry.
342      * If contributions changed since they have been added to the registry (i.e., plugin.xml
343      * file was modified since the last run), the value of the {@link #getContributionsTimestamp()}
344      * will change and no longer will be the same as the value tracked by the registry. In this case
345      * the cache is considered to be invalid and the registry is going to be re-populated form scratch.
346      * </p><p>
347      * (The word "timestamp" is used very loosely here. In this context, "timestamp" is more likely
348      * to be a hash value aggregating a number of actual timestamps from the contributions.)
349      * </p><p>
350      * This method may return 0 to indicate that no time stamp verification is required.
351      * </p>
352      * @return a value corresponding to the last mofification time of contributions contained
353      * in the registry
354      */

355     public long getContributionsTimestamp() {
356         return 0;
357     }
358
359     /**
360      * Returns the parser used by the registry to parse descriptions of extension points and extensions.
361      * This method must not return <code>null</code>.
362      *
363      * @return this strategy's parser
364      * @see org.eclipse.core.runtime.IExtensionRegistry#addContribution(java.io.InputStream, IContributor, boolean, String, ResourceBundle, Object)
365      */

366     public SAXParserFactory JavaDoc getXMLParser() {
367         if (theXMLParserFactory == null)
368             theXMLParserFactory = SAXParserFactory.newInstance();
369         return theXMLParserFactory;
370     }
371 }
372
Popular Tags