1 11 package org.eclipse.help.internal.context; 12 13 import java.io.FileNotFoundException ; 14 import java.io.InputStream ; 15 import java.util.ArrayList ; 16 import java.util.HashMap ; 17 import java.util.List ; 18 import java.util.Map ; 19 20 import javax.xml.transform.TransformerException ; 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 ; 40 import org.w3c.dom.Element ; 41 import org.w3c.dom.Node ; 42 43 47 public class ContextFileProvider extends AbstractContextProvider { 48 49 private static final String EXTENSION_POINT_CONTEXTS = "org.eclipse.help.contexts"; private static final String ELEMENT_CONTEXTS = "contexts"; private static final String ATTRIBUTE_FILE = "file"; private static final String ATTRIBUTE_PLUGIN = "plugin"; 54 private Map pluginContextsByLocale; 56 57 private Map descriptorsByPluginId; 59 60 private Map contextFilesByLocale; 62 63 private DocumentProcessor processor; 64 private DocumentReader reader; 65 private DocumentWriter writer; 66 private Map requiredAttributes; 67 68 public IContext getContext(String contextId, String locale) { 69 int index = contextId.lastIndexOf('.'); 70 String pluginId = contextId.substring(0, index); 71 String shortContextId = contextId.substring(index + 1); 72 73 if (pluginContextsByLocale == null) { 74 pluginContextsByLocale = new HashMap (); 75 } 76 Map pluginContexts = (Map )pluginContextsByLocale.get(locale); 77 if (pluginContexts == null) { 78 pluginContexts = new HashMap (); 79 pluginContextsByLocale.put(locale, pluginContexts); 80 } 81 Map [] contexts = (Map [])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 98 public String [] getPlugins() { 99 Map associations = getPluginAssociations(); 100 return (String [])associations.keySet().toArray(new String [associations.size()]); 101 } 102 103 107 private Map getPluginAssociations() { 108 if (descriptorsByPluginId == null) { 109 descriptorsByPluginId = new HashMap (); 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 declaringPluginId = elements[i].getDeclaringExtension().getContributor().getName(); 114 String file = elements[i].getAttribute(ATTRIBUTE_FILE); 115 String plugin = elements[i].getAttribute(ATTRIBUTE_PLUGIN); 116 String 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 139 private Map [] getPluginContexts(String pluginId, String locale) { 140 List maps = new ArrayList (); 141 Map associations = getPluginAssociations(); 142 ContextFile[] descriptors = (ContextFile[])associations.get(pluginId); 143 for (int i=0;i<descriptors.length;++i) { 144 Map contexts = getContexts(descriptors[i], locale); 145 if (contexts != null) { 146 maps.add(contexts); 147 } 148 } 149 return (Map [])maps.toArray(new Map [maps.size()]); 150 } 151 152 156 private Map getContexts(ContextFile descriptor, String locale) { 157 if (contextFilesByLocale == null) { 158 contextFilesByLocale = new HashMap (); 159 } 160 Map contextsByDescriptor = (Map )contextFilesByLocale.get(locale); 161 if (contextsByDescriptor == null) { 162 contextsByDescriptor = new HashMap (); 163 contextFilesByLocale.put(locale, contextsByDescriptor); 164 } 165 Map contexts = (Map )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 180 private Map loadContexts(ContextFile descriptor, String locale) { 181 try { 182 InputStream 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())) { 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 IUAElement[] children = root.getChildren(); 203 Map contexts = new HashMap (); 204 for (int i=0;i<children.length;++i) { 205 if (children[i] instanceof Context) { 206 Context context = (Context)children[i]; 207 String id = context.getId(); 208 if (id != null) { 209 contexts.put(id, context); 210 } 211 } 212 } 213 return contexts; 214 } 215 else { 216 String msg = "Required root element \"contexts\" missing from context-sensitive help file \"/" + descriptor.getBundleId() + '/' + descriptor.getFile() + "\" (skipping)"; HelpPlugin.logError(msg); 218 } 219 } 220 else { 221 throw new FileNotFoundException (); 222 } 223 } 224 catch (Throwable t) { 225 String msg = "Error reading context-sensitive help file /\"" + descriptor.getBundleId() + '/' + descriptor.getFile() + "\" (skipping file)"; HelpPlugin.logError(msg, t); 227 } 228 return null; 229 } 230 231 private Map getRequiredAttributes() { 232 if (requiredAttributes == null) { 233 requiredAttributes = new HashMap (); 234 requiredAttributes.put(Context.NAME, new String [] { Context.ATTRIBUTE_ID }); 235 requiredAttributes.put(Topic.NAME, new String [] { Topic.ATTRIBUTE_LABEL, Topic.ATTRIBUTE_HREF }); 236 requiredAttributes.put("anchor", new String [] { "id" }); requiredAttributes.put("include", new String [] { "path" }); } 239 return requiredAttributes; 240 } 241 242 249 private class NormalizeHandler extends ProcessorHandler { 250 public short handle(UAElement element, String 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 buf = new StringBuffer (); 256 Element description = ((UAElement)children[0]).element; 257 Node 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 e) { 270 String msg = "Internal error while normalizing context-sensitive help descriptions"; HelpPlugin.logError(msg, e); 272 } 273 } 274 Node old = node; 275 node = node.getNextSibling(); 276 description.removeChild(old); 277 } 278 Document 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 href = topic.getHref(); 285 if (href != null) { 286 int index = id.indexOf('/', 1); 287 if (index != -1) { 288 String pluginId = id.substring(1, index); 289 topic.setHref(HrefUtil.normalizeHref(pluginId, href)); 290 } 291 } 292 } 293 return UNHANDLED; 295 } 296 } 297 } 298 | Popular Tags |