KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > help > internal > util > ResourceLocator


1 /*******************************************************************************
2  * Copyright (c) 2000, 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.help.internal.util;
12
13 import java.io.IOException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.net.URL JavaDoc;
16 import java.net.URLConnection JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Enumeration JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.HashSet JavaDoc;
21 import java.util.Hashtable JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Locale JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.FileLocator;
29 import org.eclipse.core.runtime.IConfigurationElement;
30 import org.eclipse.core.runtime.IExtension;
31 import org.eclipse.core.runtime.IExtensionDelta;
32 import org.eclipse.core.runtime.IPath;
33 import org.eclipse.core.runtime.IRegistryChangeEvent;
34 import org.eclipse.core.runtime.IRegistryChangeListener;
35 import org.eclipse.core.runtime.Path;
36 import org.eclipse.core.runtime.Platform;
37 import org.eclipse.help.IHelpContentProducer;
38 import org.eclipse.help.internal.HelpPlugin;
39 import org.osgi.framework.Bundle;
40
41 public class ResourceLocator {
42
43     public static final String JavaDoc CONTENTPRODUCER_XP_NAME = "contentProducer"; //$NON-NLS-1$
44
public static final String JavaDoc BINDING = "binding"; //$NON-NLS-1$
45

46     public static final String JavaDoc CONTENTPRODUCER_XP_FULLNAME = HelpPlugin.PLUGIN_ID
47             + "." + CONTENTPRODUCER_XP_NAME; //$NON-NLS-1$
48

49     private static Hashtable JavaDoc zipCache = new Hashtable JavaDoc();
50
51     private static final Object JavaDoc ZIP_NOT_FOUND = new Object JavaDoc();
52
53     // Indicates there is no dynamic content provider for a particular plugin
54
private static final Object JavaDoc STATIC_DOCS_ONLY = ZIP_NOT_FOUND;
55
56     // Map of document content providers by plug-in ID;
57
private static Map JavaDoc contentProducers = new HashMap JavaDoc(2, 0.5f);
58
59     static class ProducerDescriptor {
60
61         private IHelpContentProducer producer;
62         private IConfigurationElement config;
63
64         public ProducerDescriptor(IConfigurationElement config) {
65             this.config = config;
66         }
67
68         public boolean matches(String JavaDoc refId) {
69             IExtension ex = config.getDeclaringExtension();
70             String JavaDoc id = ex.getUniqueIdentifier();
71             return id != null && id.equals(refId);
72         }
73         
74         public void reset() {
75             producer = null;
76         }
77
78         public IHelpContentProducer getProducer() {
79             if (producer == null) {
80                 try {
81                     Object JavaDoc o = config.createExecutableExtension("producer"); //$NON-NLS-1$
82
if (o instanceof IHelpContentProducer)
83                         producer = (IHelpContentProducer) o;
84                 } catch (CoreException ce) {
85                     HelpPlugin
86                             .logError(
87                                     "Exception occurred creating help content producer for plug-in " + config.getContributor().getName() + ".", ce); //$NON-NLS-1$ //$NON-NLS-2$
88
}
89             }
90             return producer;
91         }
92     }
93     static {
94         Platform.getExtensionRegistry().addRegistryChangeListener(new IRegistryChangeListener() {
95
96             /*
97              * (non-Javadoc)
98              *
99              * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
100              */

101             public void registryChanged(IRegistryChangeEvent event) {
102                 IExtensionDelta[] deltas = event.getExtensionDeltas(HelpPlugin.PLUGIN_ID,
103                         CONTENTPRODUCER_XP_NAME);
104                 for (int i = 0; i < deltas.length; i++) {
105                     IExtension extension = deltas[i].getExtension();
106                     String JavaDoc affectedPlugin = extension.getContributor().getName();
107                     // reset producer for the affected plugin,
108
// it will be recreated on demand
109
synchronized (contentProducers) {
110                         Object JavaDoc obj = contentProducers.get(affectedPlugin);
111                         if (obj instanceof ProducerDescriptor) {
112                             ProducerDescriptor desc = (ProducerDescriptor) obj;
113                             desc.reset();
114                         }
115                     }
116                 }
117             }
118         });
119     }
120
121     /**
122      * Obtains content proivider for a documentation plug-in, creates one if necessary.
123      *
124      * @param pluginId
125      * @return ITopicContentProvider or null
126      */

127     private static IHelpContentProducer getContentProducer(String JavaDoc pluginId) {
128         synchronized (contentProducers) {
129             Object JavaDoc obj = getProducerDescriptor(pluginId);
130             if (obj == null || obj == STATIC_DOCS_ONLY)
131                 return null;
132             return ((ProducerDescriptor) obj).getProducer();
133         }
134     }
135
136     private static Object JavaDoc getProducerDescriptor(String JavaDoc pluginId) {
137         Object JavaDoc descriptor = contentProducers.get(pluginId);
138         if (descriptor == null) {
139             // first time for the plug-in, so attempt to
140
// find and instantiate provider
141
descriptor = createContentProducer(pluginId);
142             if (descriptor == null) {
143                 descriptor = STATIC_DOCS_ONLY;
144             }
145             contentProducers.put(pluginId, descriptor);
146         }
147         return descriptor;
148     }
149
150     /**
151      * Creates content proivider for a documentation plug-in
152      *
153      * @param pluginId
154      * @return ITopicContentProvider or null
155      */

156     private static ProducerDescriptor createContentProducer(String JavaDoc pluginId) {
157         IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(
158                 CONTENTPRODUCER_XP_FULLNAME);
159         if (elements.length == 0) {
160             return null;
161         }
162         
163         for (int i = 0; i < elements.length; i++) {
164             IConfigurationElement element = elements[i];
165             if (!elements[i].getContributor().getName().equals(pluginId)) {
166                 continue;
167             }
168             if (BINDING.equals(element.getName())) {
169                 // producer binding - locate the descriptor
170
// with the matching reference Id
171
String JavaDoc refId = element.getAttribute("producerId"); //$NON-NLS-1$
172
if (refId != null) {
173                     return findContentProducer(elements, refId);
174                 }
175             } else if (CONTENTPRODUCER_XP_NAME.equals(element.getName())) {
176                 return new ProducerDescriptor(element);
177             }
178         }
179         return null;
180     }
181
182     private static ProducerDescriptor findContentProducer(IConfigurationElement [] elements, String JavaDoc refId) {
183         // try existing ones
184
for (Iterator JavaDoc iter = contentProducers.values().iterator(); iter.hasNext();) {
185             Object JavaDoc obj = iter.next();
186             if (obj instanceof ProducerDescriptor) {
187                 ProducerDescriptor desc = (ProducerDescriptor) obj;
188                 if (desc.matches(refId))
189                     return desc;
190             }
191         }
192         // not created yet. Find the matching configuration element,
193
// take its contributing pluginId and get the descriptor
194
// for that plug-in
195
for (int i=0; i<elements.length; i++) {
196             if (CONTENTPRODUCER_XP_NAME.equals(elements[i].getName())) {
197                 String JavaDoc id = elements[i].getDeclaringExtension().getUniqueIdentifier();
198                 if (refId.equals(id)) {
199                     Object JavaDoc obj = getProducerDescriptor(elements[i].getContributor().getName());
200                     if (obj instanceof ProducerDescriptor)
201                         return (ProducerDescriptor)obj;
202                 }
203             }
204         }
205         return null;
206     }
207
208     /**
209      * Opens an input stream to a file contained in a plugin. This includes NL lookup.
210      */

211     public static InputStream JavaDoc openFromProducer(Bundle pluginDesc, String JavaDoc file, String JavaDoc locale) {
212         IHelpContentProducer producer = getContentProducer(pluginDesc.getSymbolicName());
213         if (producer == null) {
214             return null;
215         }
216         if (locale == null || locale.length() <= 0) {
217             locale = Platform.getNL();
218         }
219         Locale JavaDoc l;
220         if (locale.length() >= 5) {
221             l = new Locale JavaDoc(locale.substring(0, 2), locale.substring(3, 5));
222         } else if (locale.length() >= 2) {
223             l = new Locale JavaDoc(locale.substring(0, 2), ""); //$NON-NLS-1$
224
} else {
225             l = Locale.getDefault();
226         }
227         return producer.getInputStream(pluginDesc.getSymbolicName(), file, l);
228     }
229
230     /**
231      * Opens an input stream to a file contained in a plugin. This includes includes OS, WS and NL
232      * lookup.
233      *
234      * @param pluginId
235      * the plugin id of the plugin that contains the file you are trying to find
236      * @param file
237      * the relative path of the file to find
238      * @param locale
239      * the locale used as an override or <code>null</code> to use the default locale
240      *
241      * @return an InputStream to the file or <code>null</code> if the file wasn't found
242      */

243     public static InputStream JavaDoc openFromPlugin(String JavaDoc pluginId, String JavaDoc file, String JavaDoc locale) {
244         Bundle bundle = Platform.getBundle(pluginId);
245         if (bundle != null)
246             return openFromPlugin(bundle, file, locale);
247         return null;
248     }
249
250     /**
251      * Opens an input stream to a file contained in a zip in a plugin. This includes OS, WS and NL
252      * lookup.
253      *
254      * @param pluginDesc
255      * the plugin description of the plugin that contains the file you are trying to find
256      * @param file
257      * the relative path of the file to find
258      * @param locale
259      * the locale used as an override or <code>null</code> to use the default locale
260      *
261      * @return an InputStream to the file or <code>null</code> if the file wasn't found
262      */

263     public static InputStream JavaDoc openFromZip(Bundle pluginDesc, String JavaDoc zip, String JavaDoc file, String JavaDoc locale) {
264
265         String JavaDoc pluginID = pluginDesc.getSymbolicName();
266         Map JavaDoc cache = zipCache;
267         ArrayList JavaDoc pathPrefix = getPathPrefix(locale);
268
269         for (int i = 0; i < pathPrefix.size(); i++) {
270
271             // finds the zip file by either using a cached location, or
272
// calling Platform.find - the result is cached for future use.
273
Object JavaDoc cached = cache.get(pluginID + '/' + pathPrefix.get(i) + zip);
274             if (cached == null) {
275                 try {
276                     URL JavaDoc url = FileLocator.find(pluginDesc, new Path(pathPrefix.get(i) + zip), null);
277                     if (url != null) {
278                         URL JavaDoc realZipURL = FileLocator.toFileURL(FileLocator.resolve(url));
279                         cached = realZipURL.toExternalForm();
280                     } else {
281                         cached = ZIP_NOT_FOUND;
282                     }
283                 } catch (IOException JavaDoc ioe) {
284                     cached = ZIP_NOT_FOUND;
285                 }
286                 // cache it
287
cache.put(pluginID + '/' + pathPrefix.get(i) + zip, cached);
288             }
289
290             if (cached == ZIP_NOT_FOUND || cached.toString().startsWith("jar:")) //$NON-NLS-1$
291
continue;
292
293             // cached should be a zip file that is actually on the filesystem
294
// now check if the file is in this zip
295
try {
296                 URL JavaDoc jurl = new URL JavaDoc("jar", "", (String JavaDoc) cached + "!/" + file); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
297
URLConnection JavaDoc jconnection = jurl.openConnection();
298                 jconnection.setDefaultUseCaches(false);
299                 jconnection.setUseCaches(false);
300                 return jconnection.getInputStream();
301             } catch (IOException JavaDoc ioe) {
302                 // a file not found exception is an io exception
303
continue;
304             }
305
306         } // end for loop
307

308         // we didn't find the file in any zip
309
return null;
310     }
311
312     /**
313      * Opens an input stream to a file contained in a plugin. This includes includes OS, WS and NL
314      * lookup.
315      *
316      * @param pluginDesc
317      * the plugin description of the plugin that contains the file you are trying to find
318      * @param file
319      * the relative path of the file to find
320      * @param locale
321      * the locale used as an override or <code>null</code> to use the default locale
322      *
323      * @return an InputStream to the file or <code>null</code> if the file wasn't found
324      */

325     public static InputStream JavaDoc openFromPlugin(Bundle pluginDesc, String JavaDoc file, String JavaDoc locale) {
326
327         ArrayList JavaDoc pathPrefix = getPathPrefix(locale);
328         URL JavaDoc flatFileURL = find(pluginDesc, new Path(file), pathPrefix);
329         if (flatFileURL != null)
330             try {
331                 return flatFileURL.openStream();
332             } catch (IOException JavaDoc e) {
333                 return null;
334             }
335         return null;
336     }
337
338
339
340     /*
341      * Search the ws, os then nl for a resource. Platform.find can't be used directly with $nl$,
342      * $os$ or $ws$ becuase the root directory will be searched too early.
343      */

344     public static URL JavaDoc find(Bundle pluginDesc, IPath flatFilePath, ArrayList JavaDoc pathPrefix) {
345
346         // try to find the actual file.
347
for (int i = 0; i < pathPrefix.size(); i++) {
348             URL JavaDoc url = FileLocator.find(pluginDesc, new Path((String JavaDoc) pathPrefix.get(i) + flatFilePath), null);
349             if (url != null)
350                 return url;
351         }
352         return null;
353     }
354
355     public static void clearZipCache() {
356         zipCache = new Hashtable JavaDoc();
357     }
358
359     /*
360      * Gets an ArrayList that has the path prefixes to search.
361      *
362      * @param locale the locale used as an override or <code>null</code> to use the default locale
363      * @return an ArrayList that has path prefixes that need to be search. The returned ArrayList
364      * will have an entry for the root of the plugin.
365      */

366     public static ArrayList JavaDoc getPathPrefix(String JavaDoc locale) {
367         ArrayList JavaDoc pathPrefix = new ArrayList JavaDoc(5);
368         // TODO add override for ws and os similar to how it's done with locale
369
// now
370
String JavaDoc ws = Platform.getWS();
371         String JavaDoc os = Platform.getOS();
372         if (locale == null)
373             locale = Platform.getNL();
374
375         if (ws != null)
376             pathPrefix.add("ws/" + ws + '/'); //$NON-NLS-1$
377

378         if (os != null && !os.equals("OS_UNKNOWN")) //$NON-NLS-1$
379
pathPrefix.add("os/" + os + '/'); //$NON-NLS-1$
380

381         if (locale != null && locale.length() >= 5)
382             pathPrefix.add("nl/" + locale.substring(0, 2) + '/' + locale.substring(3, 5) + '/'); //$NON-NLS-1$
383

384         if (locale != null && locale.length() >= 2)
385             pathPrefix.add("nl/" + locale.substring(0, 2) + '/'); //$NON-NLS-1$
386

387         // the plugin root
388
pathPrefix.add(""); //$NON-NLS-1$
389

390         return pathPrefix;
391     }
392
393     /**
394      * Finds all topics under specified directory (recursively). This includes includes OS, WS and
395      * NL lookup.
396      *
397      * @param pluginDesc
398      * the plugin description of the plugin that contains the file you are trying to find
399      * @param directory
400      * the relative path of the directory
401      * @param locale
402      * the locale used as an override or <code>null</code> to use the default locale
403      *
404      * @return an InputStream to the file or <code>null</code> if the file wasn't found
405      */

406     public static Set JavaDoc findTopicPaths(Bundle pluginDesc, String JavaDoc directory, String JavaDoc locale) {
407         Set JavaDoc ret = new HashSet JavaDoc();
408         findTopicPaths(pluginDesc, directory, locale, ret);
409         return ret;
410     }
411
412     /**
413      * @param pluginDesc
414      * @param directory
415      * @param locale
416      * @param paths
417      */

418     private static void findTopicPaths(Bundle pluginDesc, String JavaDoc directory, String JavaDoc locale, Set JavaDoc paths) {
419         if (directory.endsWith("/")) //$NON-NLS-1$
420
directory = directory.substring(0, directory.length() - 1);
421         ArrayList JavaDoc pathPrefix = getPathPrefix(locale);
422         for (int i = 0; i < pathPrefix.size(); i++) {
423             String JavaDoc path = pathPrefix.get(i) + directory;
424             if (path.length() == 0)
425                 path = "/"; //$NON-NLS-1$
426
Enumeration JavaDoc entries = pluginDesc.getEntryPaths(path);
427             if (entries != null) {
428                 while (entries.hasMoreElements()) {
429                     String JavaDoc topicPath = (String JavaDoc) entries.nextElement();
430                     if (topicPath.endsWith("/")) { //$NON-NLS-1$
431
findTopicPaths(pluginDesc, topicPath, locale, paths);
432                     } else {
433                         paths.add(topicPath);
434                     }
435                 }
436             }
437         }
438     }
439 }
440
Popular Tags