KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > registry > RegistryCacheReader


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

11
12 package org.eclipse.core.internal.registry;
13
14 import java.io.*;
15 import java.util.ArrayList JavaDoc;
16 import java.util.List JavaDoc;
17 import org.eclipse.core.internal.runtime.InternalPlatform;
18 import org.eclipse.core.internal.runtime.Policy;
19 import org.eclipse.core.runtime.*;
20
21 /**
22  * Failure reporting strategy:
23  * - when reading an identified element (bundles, extension points and extensions),
24  * catch any IOExceptions and rethrow them wrapped into a InvalidRegistryCacheException
25  * that describes where the error happened
26  * - IOExceptions while reading non-identified elements (configuration elements and properties)
27  * are just propagated to their callers
28  * - the public entry points will catch any exceptions to ensure they are logged and return a valid
29  * value instead (for instance, a null reference or an empty array)
30  */

31 public class RegistryCacheReader {
32
33     MultiStatus problems = null;
34     // objectTable will be an array list of objects. The objects will be things
35
// like a plugin descriptor, extension point, etc. The integer
36
// index value will be used in the cache to allow cross-references in the
37
// cached registry.
38
protected List JavaDoc objectTable = null;
39     private boolean lazilyLoadExtensions;
40     private boolean flushableExtensions = true;
41     // indicates we failed load configuration elements lazily
42
private boolean failed;
43     protected File cacheFile;
44
45     public static final byte REGISTRY_CACHE_VERSION = 7;
46     public static final byte NULL = 0;
47     public static final byte OBJECT = 1;
48     public static final byte INDEX = 2;
49
50     public RegistryCacheReader(File cacheFile, MultiStatus problems, boolean lazilyLoadExtensions, boolean flushable) {
51         super();
52         this.cacheFile = cacheFile;
53         this.problems = problems;
54         this.lazilyLoadExtensions = lazilyLoadExtensions;
55         this.flushableExtensions = flushable;
56         objectTable = new ArrayList JavaDoc();
57     }
58
59     public RegistryCacheReader(File cacheFile, MultiStatus problems) {
60         this(cacheFile, problems, false, true);
61     }
62
63     private int addToObjectTable(Object JavaDoc object) {
64         objectTable.add(object);
65         // return the index of the object just added (i.e. size - 1)
66
return (objectTable.size() - 1);
67     }
68
69     private void debug(String JavaDoc msg) {
70         System.out.println("RegistryCacheReader: " + msg); //$NON-NLS-1$
71
}
72
73     private boolean readHeaderInformation(DataInputStream in, long expectedTimestamp) throws InvalidRegistryCacheException {
74         try {
75             if (in.readInt() != REGISTRY_CACHE_VERSION)
76                 return false;
77             long installStamp = in.readLong();
78             long registryStamp = in.readLong();
79             String JavaDoc osStamp = in.readUTF();
80             String JavaDoc windowsStamp = in.readUTF();
81             String JavaDoc localeStamp = in.readUTF();
82             InternalPlatform info = InternalPlatform.getDefault();
83             return ((expectedTimestamp == 0 || expectedTimestamp == registryStamp) && (installStamp == info.getStateTimeStamp()) && (osStamp.equals(info.getOS())) && (windowsStamp.equals(info.getWS())) && (localeStamp.equals(info.getNL())));
84         } catch (IOException e) {
85             throw new InvalidRegistryCacheException(Policy.bind("meta.regCacheIOExceptionReading", "HeaderInformation"), e); //$NON-NLS-1$//$NON-NLS-2$
86
}
87     }
88
89     private void skipConfigurationElement(RegistryModelObject parent, DataInputStream in) throws IOException {
90         readCachedString(in, false); //read name
91
skipString(in); //skip value
92

93         int length = in.readInt();
94         for (int i = 0; i < length; i++) {
95             skipConfigurationProperty(in);
96         }
97         length = in.readInt();
98         for (int i = 0; i < length; i++) {
99             skipConfigurationElement(null, in);
100         }
101     }
102
103     private ConfigurationElement readConfigurationElement(RegistryModelObject parent, DataInputStream in) throws IOException {
104         ConfigurationElement result = new ConfigurationElement();
105         result.setParent(parent);
106         result.setName(readCachedString(in, false));
107         result.setValue(readString(in, false));
108
109         int length = in.readInt();
110         ConfigurationProperty[] properties = new ConfigurationProperty[length];
111         for (int i = 0; i < length; i++) {
112             properties[i] = readConfigurationProperty(in);
113         }
114         result.setProperties(properties);
115
116         length = in.readInt();
117         IConfigurationElement[] elements = new ConfigurationElement[length];
118         for (int i = 0; i < length; i++) {
119             elements[i] = readConfigurationElement(result, in);
120         }
121         result.setChildren(elements);
122         return result;
123     }
124
125     private void skipConfigurationProperty(DataInputStream in) throws IOException {
126         readCachedString(in, false); //Read the name
127
skipString(in); // skip the value
128
}
129
130     private ConfigurationProperty readConfigurationProperty(DataInputStream in) throws IOException {
131         String JavaDoc name = readCachedString(in, false);
132         ConfigurationProperty result = new ConfigurationProperty();
133         result.setName(name);
134         result.setValue(readString(in, false));
135         return result;
136     }
137
138     private Extension readExtension(DataInputStream in) throws InvalidRegistryCacheException {
139         Extension result = null;
140         try {
141             result = (Extension) readIndex(in);
142             if (result != null)
143                 return result;
144             result = flushableExtensions ? new FlushableExtension() : new Extension();
145             addToObjectTable(result);
146             result.setSimpleIdentifier(readString(in, false));
147             result.setParent(readBundleModel(in));
148             result.setName(readString(in, false));
149             result.setExtensionPointIdentifier(readCachedString(in, false));
150             result.setSubElements(readSubElements(result, in));
151             return result;
152         } catch (IOException e) {
153             String JavaDoc extensionId = null;
154             if (result != null && result.getParent() != null)
155                 extensionId = result.getParentIdentifier() + "." + result.getSimpleIdentifier(); //$NON-NLS-1$
156
throw new InvalidRegistryCacheException(Policy.bind("meta.regCacheIOExceptionReading", "extension: " + extensionId), e); //$NON-NLS-1$ //$NON-NLS-2$
157
}
158     }
159
160     private ExtensionPoint readExtensionPoint(Namespace bundle, DataInputStream in) throws InvalidRegistryCacheException {
161         ExtensionPoint result = null;
162         try {
163             result = (ExtensionPoint) readIndex(in);
164             if (result != null)
165                 return result;
166             result = new ExtensionPoint();
167             addToObjectTable(result);
168             result.setParent(bundle);
169             result.setSimpleIdentifier(readString(in, true));
170             result.setName(readString(in, false));
171             result.setSchema(readString(in, false));
172
173             // Now do the extensions.
174
int length = in.readInt();
175             IExtension[] extensions = new Extension[length];
176             for (int i = 0; i < length; i++)
177                 extensions[i] = readExtension(in);
178             result.setExtensions(extensions);
179             return result;
180         } catch (IOException e) {
181             String JavaDoc extensionPointId = null;
182             if (result != null && result.getParent() != null)
183                 extensionPointId = result.getUniqueIdentifier();
184             throw new InvalidRegistryCacheException(Policy.bind("meta.regCacheIOExceptionReading", "extension point: " + extensionPointId), e); //$NON-NLS-1$ //$NON-NLS-2$
185
}
186     }
187
188     private Namespace readBundleModel(DataInputStream in) throws InvalidRegistryCacheException {
189         Namespace result = null;
190         try {
191             result = (Namespace) readIndex(in);
192             if (result != null)
193                 return result;
194             result = new Namespace();
195             addToObjectTable(result);
196             result.setUniqueIdentifier(readCachedString(in, true));
197             result.setBundle(InternalPlatform.getDefault().getBundleContext().getBundle(in.readLong()));
198             result.setParent(readRegistry(in));
199             result.setHostIdentifier(readCachedString(in, false));
200
201             // now do extension points
202
int length = in.readInt();
203             IExtensionPoint[] extensionPoints = new ExtensionPoint[length];
204             for (int i = 0; i < length; i++)
205                 extensionPoints[i] = readExtensionPoint(result, in);
206             result.setExtensionPoints(extensionPoints);
207
208             // and then extensions
209
length = in.readInt();
210             IExtension[] extensions = flushableExtensions ? new FlushableExtension[length] : new Extension[length];
211             for (int i = 0; i < length; i++)
212                 extensions[i] = readExtension(in);
213             result.setExtensions(extensions);
214             return result;
215         } catch (IOException e) {
216             String JavaDoc bundleId = (result == null || result.getUniqueIdentifier() == null) ? "<not available>" : result.getUniqueIdentifier(); //$NON-NLS-1$
217
throw new InvalidRegistryCacheException(Policy.bind("meta.regCacheIOExceptionReading", "plugin: " + bundleId), e); //$NON-NLS-1$//$NON-NLS-2$
218
}
219     }
220
221     private ExtensionRegistry readCache(DataInputStream in, long expectedTimestamps) throws InvalidRegistryCacheException {
222         if (!readHeaderInformation(in, expectedTimestamps)) {
223             if (InternalPlatform.DEBUG_REGISTRY)
224                 debug("Cache header information out of date - ignoring cache"); //$NON-NLS-1$
225
return null;
226         }
227         return readRegistry(in);
228     }
229
230     private ExtensionRegistry readRegistry(DataInputStream in) throws InvalidRegistryCacheException {
231         try {
232             ExtensionRegistry result = (ExtensionRegistry) readIndex(in);
233             if (result != null)
234                 return result;
235
236             result = new ExtensionRegistry();
237             if (lazilyLoadExtensions)
238                 result.setCacheReader(this);
239             addToObjectTable(result);
240             // if there are no plugins in the registry, return null instead of
241
// an empty registry?
242
int length = in.readInt();
243             if (length == 0)
244                 return null;
245             for (int i = 0; i < length; i++)
246                 result.basicAdd(readBundleModel(in), false);
247             if (lazilyLoadExtensions)
248                 result.setCacheReader(this);
249             return result;
250         } catch (IOException e) {
251             throw new InvalidRegistryCacheException(Policy.bind("meta.regCacheIOExceptionReading", "ExtensionRegistry"), e); //$NON-NLS-1$//$NON-NLS-2$
252
}
253     }
254
255     private ConfigurationElement[] readSubElements(Extension parent, DataInputStream in) throws IOException {
256         int type = in.readByte();
257         if (type == NULL)
258             return null;
259
260         //Here type is OBJECT
261
// the first field is extension sub-elements data offset
262
int offset = in.readInt();
263
264         if (lazilyLoadExtensions) {
265             Extension extension = parent;
266             extension.setSubElementsCacheOffset(offset);
267             skipBasicSubElements(parent, in);
268             extension.setFullyLoaded(false);
269             return null;
270         }
271         return readBasicSubElements(parent, in);
272     }
273
274     private void skipBasicSubElements(Extension parent, DataInputStream in) throws IOException {
275         int length = in.readInt();
276         for (int i = 0; i < length; i++) {
277             skipConfigurationElement(parent, in);
278         }
279     }
280
281     private ConfigurationElement[] readBasicSubElements(Extension parent, DataInputStream in) throws IOException {
282         // read the number of sub elements to load
283
int length = in.readInt();
284
285         ConfigurationElement[] result = new ConfigurationElement[length];
286         for (int i = 0; i < length; i++) {
287             result[i] = readConfigurationElement(parent, in);
288         }
289         return result;
290     }
291
292     private String JavaDoc readString(DataInputStream in, boolean intern) throws IOException {
293         byte type = in.readByte();
294         if (type == NULL)
295             return null;
296         if (intern)
297             return in.readUTF().intern();
298         else
299             return in.readUTF();
300     }
301
302     private void skipString(DataInputStream in) throws IOException {
303         byte type = in.readByte();
304         if (type == NULL)
305             return;
306         int utfLength = in.readUnsignedShort();
307         byte bytearr[] = new byte[utfLength];
308         in.readFully(bytearr, 0, utfLength);
309     }
310
311     private String JavaDoc readCachedString(DataInputStream in, boolean intern) throws IOException {
312         byte type = in.readByte();
313         if (type == NULL)
314             return null;
315
316         if (type == INDEX)
317             return (String JavaDoc) objectTable.get(in.readInt());
318
319         String JavaDoc stringRead = null;
320         if (intern)
321             stringRead = in.readUTF().intern();
322         else
323             stringRead = in.readUTF();
324         addToObjectTable(stringRead);
325         return stringRead;
326     }
327
328     private Object JavaDoc readIndex(DataInputStream in) throws IOException {
329         byte type = in.readByte();
330         return type == INDEX ? objectTable.get(in.readInt()) : null;
331     }
332
333     private DataInputStream openCacheFile() throws IOException {
334         return new DataInputStream(new BufferedInputStream(new FileInputStream(cacheFile), 2048));
335     }
336
337     /**
338      * Lazily loads an extension model's sub-elements.
339      */

340     public final ConfigurationElement[] loadConfigurationElements(Extension parent, int offset) {
341         DataInputStream in = null;
342         try {
343             in = openCacheFile();
344             in.skipBytes(offset);
345             in.readInt(); // skip the offset itself
346
return readBasicSubElements(parent, in);
347         } catch (IOException e) {
348             Throwable JavaDoc exception = InternalPlatform.DEBUG_REGISTRY ? e : null;
349             String JavaDoc message = Policy.bind("meta.unableToReadCache"); //$NON-NLS-1$
350
InternalPlatform.getDefault().log(new Status(IStatus.WARNING, Platform.PI_RUNTIME, 0, message, exception));
351         } catch (OutOfMemoryError JavaDoc oome) {
352             // catch any OutOfMemoryErrors that may have been caused by corrupted data
353
logError(oome);
354         } catch (RuntimeException JavaDoc re) {
355             // catch any ArrayIndexOutOfBounds/NullPointer/NegativeArraySize/... exceptions that may have been caused by corrupted data
356
logError(re);
357         } finally {
358             try {
359                 if (in != null)
360                     in.close();
361             } catch (IOException e) {
362                 // ignore
363
}
364         }
365         // we only get here when we have problems
366
failed = true;
367         return new ConfigurationElement[0];
368     }
369
370     boolean hasFailed() {
371         return failed;
372     }
373
374     private void logError(Throwable JavaDoc t) {
375         // log general message
376
String JavaDoc message = Policy.bind("meta.registryCacheReadProblems"); //$NON-NLS-1$
377
InternalPlatform.getDefault().log(new Status(IStatus.WARNING, Platform.PI_RUNTIME, 0, message, null));
378         // log actual error
379
Throwable JavaDoc exceptionToLog = InternalPlatform.DEBUG_REGISTRY ? t : null;
380         InternalPlatform.getDefault().log(new Status(IStatus.WARNING, Platform.PI_RUNTIME, 0, t.toString(), exceptionToLog));
381     }
382
383     public final ExtensionRegistry loadCache() {
384         return this.loadCache(0);
385     }
386
387     /*
388      * If expectedTimestamp != 0, check it against the registry timestamp if the header.
389      */

390     public final ExtensionRegistry loadCache(long expectedTimestamp) {
391         DataInputStream in = null;
392         try {
393             in = openCacheFile();
394         } catch (IOException e) {
395             Throwable JavaDoc exception = InternalPlatform.DEBUG_REGISTRY ? e : null;
396             String JavaDoc message = Policy.bind("meta.unableToReadCache"); //$NON-NLS-1$
397
InternalPlatform.getDefault().log(new Status(IStatus.WARNING, Platform.PI_RUNTIME, 0, message, exception));
398             return null;
399         }
400         try {
401             return readCache(in, expectedTimestamp);
402         } catch (InvalidRegistryCacheException e) {
403             Throwable JavaDoc exception = InternalPlatform.DEBUG_REGISTRY ? e.getCause() : null;
404             InternalPlatform.getDefault().log(new Status(IStatus.WARNING, Platform.PI_RUNTIME, 0, e.getMessage(), exception));
405         } catch (OutOfMemoryError JavaDoc oome) {
406             // catch any OutOfMemoryErrors that may have been caused by corrupted data
407
logError(oome);
408         } catch (RuntimeException JavaDoc re) {
409             // catch any ArrayIndexOutOfBounds/NullPointer/NegativeArraySize/... exceptions that may have been caused by corrupted data
410
logError(re);
411         } finally {
412             try {
413                 if (in != null)
414                     in.close();
415             } catch (IOException e) {
416                 // ignore
417
}
418         }
419         return null;
420     }
421
422     public class InvalidRegistryCacheException extends Exception JavaDoc {
423         Throwable JavaDoc cause = null;
424
425         public InvalidRegistryCacheException(String JavaDoc msg, Throwable JavaDoc cause) {
426             super(msg);
427             this.cause = cause;
428         }
429
430         public InvalidRegistryCacheException(String JavaDoc string) {
431             super(string);
432         }
433
434         public Throwable JavaDoc getCause() {
435             return cause;
436         }
437     }
438 }
Popular Tags