KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > help > internal > context > ContextFileProvider


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 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.context;
12
13 import java.io.FileNotFoundException JavaDoc;
14 import java.io.InputStream JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19
20 import javax.xml.transform.TransformerException JavaDoc;
21
22 import org.eclipse.core.runtime.IConfigurationElement;
23 import org.eclipse.core.runtime.Platform;
24 import org.eclipse.help.AbstractContextProvider;
25 import org.eclipse.help.IContext;
26 import org.eclipse.help.IUAElement;
27 import org.eclipse.help.internal.HelpPlugin;
28 import org.eclipse.help.internal.Topic;
29 import org.eclipse.help.internal.UAElement;
30 import org.eclipse.help.internal.dynamic.DocumentProcessor;
31 import org.eclipse.help.internal.dynamic.DocumentReader;
32 import org.eclipse.help.internal.dynamic.DocumentWriter;
33 import org.eclipse.help.internal.dynamic.ExtensionHandler;
34 import org.eclipse.help.internal.dynamic.IncludeHandler;
35 import org.eclipse.help.internal.dynamic.ProcessorHandler;
36 import org.eclipse.help.internal.dynamic.ValidationHandler;
37 import org.eclipse.help.internal.toc.HrefUtil;
38 import org.eclipse.help.internal.util.ResourceLocator;
39 import org.w3c.dom.Document JavaDoc;
40 import org.w3c.dom.Element JavaDoc;
41 import org.w3c.dom.Node JavaDoc;
42
43 /*
44  * Provides context-sensitive help data to the help system, contributed from
45  * context XML files.
46  */

47 public class ContextFileProvider extends AbstractContextProvider {
48
49     private static final String JavaDoc EXTENSION_POINT_CONTEXTS = "org.eclipse.help.contexts"; //$NON-NLS-1$
50
private static final String JavaDoc ELEMENT_CONTEXTS = "contexts"; //$NON-NLS-1$
51
private static final String JavaDoc ATTRIBUTE_FILE = "file"; //$NON-NLS-1$
52
private static final String JavaDoc ATTRIBUTE_PLUGIN = "plugin"; //$NON-NLS-1$
53

54     // locale -> Map(pluginId -> Map(shortContextId -> Context)[])
55
private Map JavaDoc pluginContextsByLocale;
56     
57     // pluginId -> ContextFile[]
58
private Map JavaDoc descriptorsByPluginId;
59     
60     // locale -> Map(ContextFile -> Map(shortContextId -> Context))
61
private Map JavaDoc contextFilesByLocale;
62     
63     private DocumentProcessor processor;
64     private DocumentReader reader;
65     private DocumentWriter writer;
66     private Map JavaDoc requiredAttributes;
67     
68     public IContext getContext(String JavaDoc contextId, String JavaDoc locale) {
69         int index = contextId.lastIndexOf('.');
70         String JavaDoc pluginId = contextId.substring(0, index);
71         String JavaDoc shortContextId = contextId.substring(index + 1);
72         
73         if (pluginContextsByLocale == null) {
74             pluginContextsByLocale = new HashMap JavaDoc();
75         }
76         Map JavaDoc pluginContexts = (Map JavaDoc)pluginContextsByLocale.get(locale);
77         if (pluginContexts == null) {
78             pluginContexts = new HashMap JavaDoc();
79             pluginContextsByLocale.put(locale, pluginContexts);
80         }
81         Map JavaDoc[] contexts = (Map JavaDoc[])pluginContexts.get(pluginId);
82         if (contexts == null) {
83             contexts = getPluginContexts(pluginId, locale);
84             pluginContexts.put(pluginId, contexts);
85         }
86         for (int i=0;i<contexts.length;++i) {
87             Context context = (Context)contexts[i].get(shortContextId);
88             if (context != null) {
89                 return context;
90             }
91         }
92         return null;
93     }
94     
95     /* (non-Javadoc)
96      * @see org.eclipse.help.AbstractContextProvider#getPlugins()
97      */

98     public String JavaDoc[] getPlugins() {
99         Map JavaDoc associations = getPluginAssociations();
100         return (String JavaDoc[])associations.keySet().toArray(new String JavaDoc[associations.size()]);
101     }
102
103     /*
104      * Returns a mapping of plug-in IDs to arrays of context files that apply
105      * to that plug-in (pluginId -> ContextFile[]).
106      */

107     private Map JavaDoc getPluginAssociations() {
108         if (descriptorsByPluginId == null) {
109             descriptorsByPluginId = new HashMap JavaDoc();
110             IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_CONTEXTS);
111             for (int i=0;i<elements.length;++i) {
112                 if (ELEMENT_CONTEXTS.equals(elements[i].getName())) {
113                     String JavaDoc declaringPluginId = elements[i].getDeclaringExtension().getContributor().getName();
114                     String JavaDoc file = elements[i].getAttribute(ATTRIBUTE_FILE);
115                     String JavaDoc plugin = elements[i].getAttribute(ATTRIBUTE_PLUGIN);
116                     String JavaDoc targetPluginId = (plugin == null ? declaringPluginId : plugin);
117                     ContextFile descriptor = new ContextFile(declaringPluginId, file);
118                     ContextFile[] descriptors = (ContextFile[])descriptorsByPluginId.get(targetPluginId);
119                     if (descriptors == null) {
120                         descriptors = new ContextFile[] { descriptor };
121                     }
122                     else {
123                         ContextFile[] temp = new ContextFile[descriptors.length + 1];
124                         System.arraycopy(descriptors, 0, temp, 0, descriptors.length);
125                         temp[descriptors.length] = descriptor;
126                         descriptors = temp;
127                     }
128                     descriptorsByPluginId.put(targetPluginId, descriptors);
129                 }
130             }
131         }
132         return descriptorsByPluginId;
133     }
134     
135     /*
136      * Returns the context definitions for the given plug-in and locale,
137      * as a mapping of short IDs to Context objects (shortContextId -> Context).
138      */

139     private Map JavaDoc[] getPluginContexts(String JavaDoc pluginId, String JavaDoc locale) {
140         List JavaDoc maps = new ArrayList JavaDoc();
141         Map JavaDoc associations = getPluginAssociations();
142         ContextFile[] descriptors = (ContextFile[])associations.get(pluginId);
143         for (int i=0;i<descriptors.length;++i) {
144             Map JavaDoc contexts = getContexts(descriptors[i], locale);
145             if (contexts != null) {
146                 maps.add(contexts);
147             }
148         }
149         return (Map JavaDoc[])maps.toArray(new Map JavaDoc[maps.size()]);
150     }
151     
152     /*
153      * Returns the context definitions stored in the given file for the given
154      * locale (shortContextId -> Context).
155      */

156     private Map JavaDoc getContexts(ContextFile descriptor, String JavaDoc locale) {
157         if (contextFilesByLocale == null) {
158             contextFilesByLocale = new HashMap JavaDoc();
159         }
160         Map JavaDoc contextsByDescriptor = (Map JavaDoc)contextFilesByLocale.get(locale);
161         if (contextsByDescriptor == null) {
162             contextsByDescriptor = new HashMap JavaDoc();
163             contextFilesByLocale.put(locale, contextsByDescriptor);
164         }
165         Map JavaDoc contexts = (Map JavaDoc)contextsByDescriptor.get(descriptor);
166         if (contexts == null) {
167             contexts = loadContexts(descriptor, locale);
168             if (contexts != null) {
169                 contextsByDescriptor.put(descriptor, contexts);
170             }
171         }
172         return contexts;
173     }
174     
175     /*
176      * Loads the given context file for the given locale, and returns its
177      * contents as a mapping from short context ids to Context objects
178      * (shortContextId -> Context).
179      */

180     private Map JavaDoc loadContexts(ContextFile descriptor, String JavaDoc locale) {
181         try {
182             // load the file
183
InputStream JavaDoc in = ResourceLocator.openFromPlugin(descriptor.getBundleId(), descriptor.getFile(), locale);
184             if (in != null) {
185                 if (reader == null) {
186                     reader = new DocumentReader();
187                 }
188                 UAElement root = reader.read(in);
189                 if ("contexts".equals(root.getElementName())) { //$NON-NLS-1$
190
// process dynamic content
191
if (processor == null) {
192                         processor = new DocumentProcessor(new ProcessorHandler[] {
193                             new ValidationHandler(getRequiredAttributes()),
194                             new NormalizeHandler(),
195                             new IncludeHandler(reader, locale),
196                             new ExtensionHandler(reader, locale)
197                         });
198                     }
199                     processor.process(root, '/' + descriptor.getBundleId() + '/' + descriptor.getFile());
200                     
201                     // build map
202
IUAElement[] children = root.getChildren();
203                     Map JavaDoc contexts = new HashMap JavaDoc();
204                     for (int i=0;i<children.length;++i) {
205                         if (children[i] instanceof Context) {
206                             Context context = (Context)children[i];
207                             String JavaDoc id = context.getId();
208                             if (id != null) {
209                                 contexts.put(id, context);
210                             }
211                         }
212                     }
213                     return contexts;
214                 }
215                 else {
216                     String JavaDoc msg = "Required root element \"contexts\" missing from context-sensitive help file \"/" + descriptor.getBundleId() + '/' + descriptor.getFile() + "\" (skipping)"; //$NON-NLS-1$ //$NON-NLS-2$
217
HelpPlugin.logError(msg);
218                 }
219             }
220             else {
221                 throw new FileNotFoundException JavaDoc();
222             }
223         }
224         catch (Throwable JavaDoc t) {
225             String JavaDoc msg = "Error reading context-sensitive help file /\"" + descriptor.getBundleId() + '/' + descriptor.getFile() + "\" (skipping file)"; //$NON-NLS-1$ //$NON-NLS-2$
226
HelpPlugin.logError(msg, t);
227         }
228         return null;
229     }
230     
231     private Map JavaDoc getRequiredAttributes() {
232         if (requiredAttributes == null) {
233             requiredAttributes = new HashMap JavaDoc();
234             requiredAttributes.put(Context.NAME, new String JavaDoc[] { Context.ATTRIBUTE_ID });
235             requiredAttributes.put(Topic.NAME, new String JavaDoc[] { Topic.ATTRIBUTE_LABEL, Topic.ATTRIBUTE_HREF });
236             requiredAttributes.put("anchor", new String JavaDoc[] { "id" }); //$NON-NLS-1$ //$NON-NLS-2$
237
requiredAttributes.put("include", new String JavaDoc[] { "path" }); //$NON-NLS-1$ //$NON-NLS-2$
238
}
239         return requiredAttributes;
240     }
241     
242     /*
243      * Handler that normalizes:
244      * 1. Descriptions - any child elements like bold tags are serialized and inserted into the
245      * text node under the description element.
246      * 2. Related topic hrefs - convert from relative (e.g. "path/file.html") to absolute hrefs
247      * (e.g. "/plugin.id/path/file.html").
248      */

249     private class NormalizeHandler extends ProcessorHandler {
250         public short handle(UAElement element, String JavaDoc id) {
251             if (element instanceof Context) {
252                 Context context = (Context)element;
253                 IUAElement[] children = context.getChildren();
254                 if (children.length > 0 && Context.ELEMENT_DESCRIPTION.equals(((UAElement)children[0]).getElementName())) {
255                     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
256                     Element description = ((UAElement)children[0]).element;
257                     Node JavaDoc node = description.getFirstChild();
258                     while (node != null) {
259                         if (node.getNodeType() == Node.TEXT_NODE) {
260                             buf.append(node.getNodeValue());
261                         }
262                         else if (node.getNodeType() == Node.ELEMENT_NODE) {
263                             if (writer == null) {
264                                 writer = new DocumentWriter();
265                             }
266                             try {
267                                 buf.append(writer.writeString((Element)node, false));
268                             }
269                             catch (TransformerException JavaDoc e) {
270                                 String JavaDoc msg = "Internal error while normalizing context-sensitive help descriptions"; //$NON-NLS-1$
271
HelpPlugin.logError(msg, e);
272                             }
273                         }
274                         Node JavaDoc old = node;
275                         node = node.getNextSibling();
276                         description.removeChild(old);
277                     }
278                     Document JavaDoc document = description.getOwnerDocument();
279                     description.appendChild(document.createTextNode(buf.toString()));
280                 }
281             }
282             else if (element instanceof Topic) {
283                 Topic topic = (Topic)element;
284                 String JavaDoc href = topic.getHref();
285                 if (href != null) {
286                     int index = id.indexOf('/', 1);
287                     if (index != -1) {
288                         String JavaDoc pluginId = id.substring(1, index);
289                         topic.setHref(HrefUtil.normalizeHref(pluginId, href));
290                     }
291                 }
292             }
293             // give other handlers an opportunity to process
294
return UNHANDLED;
295         }
296     }
297 }
298
Popular Tags