1 11 package org.eclipse.help.internal.search; 12 13 import java.io.IOException ; 14 import java.net.URL ; 15 import java.nio.channels.OverlappingFileLockException ; 16 import java.util.ArrayList ; 17 import java.util.Collection ; 18 import java.util.HashMap ; 19 import java.util.HashSet ; 20 import java.util.Iterator ; 21 import java.util.List ; 22 import java.util.Map ; 23 import java.util.Set ; 24 import java.util.StringTokenizer ; 25 26 import org.apache.lucene.document.Document; 27 import org.apache.lucene.search.Hits; 28 import org.eclipse.core.runtime.FileLocator; 29 import org.eclipse.core.runtime.IConfigurationElement; 30 import org.eclipse.core.runtime.IProduct; 31 import org.eclipse.core.runtime.IProgressMonitor; 32 import org.eclipse.core.runtime.OperationCanceledException; 33 import org.eclipse.core.runtime.Path; 34 import org.eclipse.core.runtime.Platform; 35 import org.eclipse.help.IHelpResource; 36 import org.eclipse.help.internal.HelpPlugin; 37 import org.eclipse.help.internal.base.BaseHelpSystem; 38 import org.eclipse.help.internal.base.HelpBasePlugin; 39 import org.eclipse.help.internal.search.IndexingOperation.IndexingException; 40 import org.eclipse.help.internal.util.URLCoder; 41 import org.eclipse.help.search.LuceneSearchParticipant; 42 import org.osgi.framework.Bundle; 43 44 47 public class LocalSearchManager { 48 49 private static final String SEARCH_PARTICIPANT_XP_FULLNAME = "org.eclipse.help.base.luceneSearchParticipants"; private static final String SEARCH_PARTICIPANT_XP_NAME = "searchParticipant"; private static final String BINDING_XP_NAME = "binding"; private static final Object PARTICIPANTS_NOT_FOUND = new Object (); 53 private Map indexes = new HashMap (); 54 private Map analyzerDescriptors = new HashMap (); 55 private Map searchParticipantsById = new HashMap (); 56 private Map searchParticipantsByPlugin = new HashMap (); 57 private ArrayList globalSearchParticipants; 58 59 private static class ParticipantDescriptor implements IHelpResource { 60 61 private IConfigurationElement element; 62 private LuceneSearchParticipant participant; 63 64 public ParticipantDescriptor(IConfigurationElement element) { 65 this.element = element; 66 } 67 68 public String getId() { 69 return element.getAttribute("id"); } 71 72 public boolean matches(String extension) { 73 String ext = element.getAttribute("extensions"); if (ext == null) 75 return false; 76 StringTokenizer stok = new StringTokenizer (ext, ","); for (; stok.hasMoreTokens();) { 78 String token = stok.nextToken().trim(); 79 if (token.equalsIgnoreCase(extension)) 80 return true; 81 } 82 return false; 83 } 84 85 public boolean hasExtensions() { 86 return element.getAttribute("extensions") != null; } 88 89 public IHelpResource getCategory() { 90 return this; 91 } 92 93 public LuceneSearchParticipant getParticipant() { 94 if (participant == null) { 95 try { 96 Object obj = element.createExecutableExtension("participant"); if (obj instanceof LuceneSearchParticipant) { 98 participant = (LuceneSearchParticipant) obj; 99 participant.init(getId()); 100 } 101 } catch (Throwable t) { 102 HelpPlugin.logError("Exception occurred creating Lucene search participant.", t); } 104 } 105 return participant; 106 } 107 108 public boolean contains(IConfigurationElement el) { 109 return element.equals(el); 110 } 111 112 public String getHref() { 113 return null; 114 } 115 116 public String getLabel() { 117 return element.getAttribute("name"); } 119 120 public URL getIconURL() { 121 String relativePath = element.getAttribute("icon"); if (relativePath == null) 123 return null; 124 String bundleId = element.getContributor().getName(); 125 Bundle bundle = Platform.getBundle(bundleId); 126 if (bundle == null) 127 return null; 128 return FileLocator.find(bundle, new Path(relativePath), null); 129 } 130 131 public void clear() { 132 if (participant != null) { 133 try { 134 participant.clear(); 135 } 136 catch (Throwable t) { 137 HelpBasePlugin.logError("Error occured in search participant's clear() operation: " + participant.getClass().getName(), t); } 139 } 140 } 141 } 142 143 151 public static List asList(Hits hits) { 152 List list = new ArrayList (hits.length()); 153 for (int i=0;i<hits.length();++i) { 154 try { 155 Document doc = hits.doc(i); 156 float score = hits.score(i); 157 String href = doc.get("name"); String summary = doc.get("summary"); String id = doc.get("id"); String participantId = doc.get("participantId"); String label = doc.get("raw_title"); boolean isPotentialHit = (doc.get("filters") != null); list.add(new SearchHit(href, label, summary, score, null, id, participantId, isPotentialHit)); 164 } 165 catch (IOException e) { 166 HelpBasePlugin.logError("An error occured while reading search hits", e); continue; 168 } 169 } 170 return list; 171 } 172 173 176 public SearchIndexWithIndexingProgress getIndex(String locale) { 177 synchronized (indexes) { 178 Object index = indexes.get(locale); 179 if (index == null) { 180 index = new SearchIndexWithIndexingProgress(locale, getAnalyzer(locale), HelpPlugin 181 .getTocManager()); 182 indexes.put(locale, index); 183 } 184 return (SearchIndexWithIndexingProgress) index; 185 } 186 } 187 188 194 private AnalyzerDescriptor getAnalyzer(String locale) { 195 AnalyzerDescriptor analyzerDesc = (AnalyzerDescriptor) analyzerDescriptors.get(locale); 197 if (analyzerDesc != null) 198 return analyzerDesc; 199 200 analyzerDesc = new AnalyzerDescriptor(locale); 202 analyzerDescriptors.put(locale, analyzerDesc); 204 String lang = analyzerDesc.getLang(); 205 if (locale != null && !locale.equals(lang)) 206 analyzerDescriptors.put(lang, analyzerDesc); 207 208 return analyzerDesc; 209 } 210 211 public static String trimQuery(String href) { 212 int qloc = href.indexOf('?'); 214 if (qloc != -1) 215 return href.substring(0, qloc); 216 return href; 217 } 218 219 public boolean isIndexable(String url) { 220 url = trimQuery(url); 221 ArrayList list = getParticipantDescriptors(getPluginId(url)); 222 if (list == null) 223 return false; 224 int dotLoc = url.lastIndexOf('.'); 225 String ext = url.substring(dotLoc + 1); 226 for (int i = 0; i < list.size(); i++) { 227 ParticipantDescriptor desc = (ParticipantDescriptor) list.get(i); 228 if (desc.matches(ext)) 229 return true; 230 } 231 return false; 232 } 233 234 242 private static boolean isParticipantEnabled(boolean headless) { 243 if (!headless) { 244 return (BaseHelpSystem.getMode() == BaseHelpSystem.MODE_WORKBENCH); 245 } 246 return true; 247 } 248 249 public static String getPluginId(String href) { 250 href = trimQuery(href); 251 if (href.charAt(0) == '/') 253 href = href.substring(1); 254 int i = href.indexOf('/'); 255 String pluginId = i == -1 ? "" : href.substring(0, i); pluginId = URLCoder.decode(pluginId); 257 if ("PRODUCT_PLUGIN".equals(pluginId)) { IProduct product = Platform.getProduct(); 259 if (product != null) { 260 pluginId = product.getDefiningBundle().getSymbolicName(); 261 } 262 } 263 return pluginId; 264 } 265 266 public LuceneSearchParticipant getGlobalParticipant(String participantId) { 267 ParticipantDescriptor desc = getGlobalParticipantDescriptor(participantId); 268 return desc != null ? desc.getParticipant() : null; 269 } 270 271 public IHelpResource getParticipantCategory(String participantId) { 272 ParticipantDescriptor desc = getGlobalParticipantDescriptor(participantId); 273 return desc != null ? desc.getCategory() : null; 274 } 275 276 public URL getParticipantIconURL(String participantId) { 277 ParticipantDescriptor desc = getGlobalParticipantDescriptor(participantId); 278 return desc != null ? desc.getIconURL() : null; 279 } 280 281 private ParticipantDescriptor getGlobalParticipantDescriptor(String participantId) { 282 if (globalSearchParticipants == null) { 283 createGlobalSearchParticipants(); 284 } 285 for (int i = 0; i < globalSearchParticipants.size(); i++) { 286 ParticipantDescriptor desc = (ParticipantDescriptor) globalSearchParticipants.get(i); 287 if (desc.getId().equals(participantId)) { 288 return desc; 289 } 290 } 291 return null; 292 } 293 294 301 public LuceneSearchParticipant getParticipant(String participantId) { 302 ParticipantDescriptor desc = (ParticipantDescriptor)searchParticipantsById.get(participantId); 303 if (desc != null) { 304 return desc.getParticipant(); 305 } 306 return null; 307 } 308 309 316 317 public LuceneSearchParticipant getParticipant(String pluginId, String fileName) { 318 ArrayList list = getParticipantDescriptors(pluginId); 319 if (list == null) 320 return null; 321 int dotLoc = fileName.lastIndexOf('.'); 322 String ext = fileName.substring(dotLoc + 1); 323 for (int i = 0; i < list.size(); i++) { 324 ParticipantDescriptor desc = (ParticipantDescriptor) list.get(i); 325 if (desc.matches(ext)) 326 return desc.getParticipant(); 327 } 328 return null; 329 } 330 331 339 public boolean isParticipantBound(String pluginId, String participantId) { 340 List list = getParticipantDescriptors(pluginId); 341 if (list != null) { 342 Iterator iter = list.iterator(); 343 while (iter.hasNext()) { 344 ParticipantDescriptor desc = (ParticipantDescriptor)iter.next(); 345 if (participantId.equals(desc.getId())) { 346 return true; 347 } 348 } 349 } 350 return false; 351 } 352 353 358 359 public Set getPluginsWithSearchParticipants() { 360 HashSet set = new HashSet (); 361 IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor( 362 SEARCH_PARTICIPANT_XP_FULLNAME); 363 364 for (int i = 0; i < elements.length; i++) { 365 IConfigurationElement element = elements[i]; 366 if (element.getName().equals("binding") || element.getName().equals("searchParticipant")) set.add(element.getContributor().getName()); 368 } 369 LuceneSearchParticipant[] gps = getGlobalParticipants(); 371 for (int i = 0; i < gps.length; i++) { 372 Set ids; 373 try { 374 ids = gps[i].getContributingPlugins(); 375 } 376 catch (Throwable t) { 377 HelpBasePlugin.logError("Error getting the contributing plugins from help search participant: " + gps[i].getClass().getName() + ". skipping this one.", t); continue; 379 } 380 set.addAll(ids); 381 } 382 return set; 383 } 384 385 389 public void clearSearchParticipants() { 390 Iterator iter = searchParticipantsById.values().iterator(); 391 while (iter.hasNext()) { 392 ParticipantDescriptor desc = (ParticipantDescriptor)iter.next(); 393 desc.clear(); 394 } 395 } 396 397 private ArrayList createSearchParticipants(String pluginId) { 398 IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor( 399 SEARCH_PARTICIPANT_XP_FULLNAME); 400 if (elements.length == 0) 401 return null; 402 ArrayList list = null; 403 404 ArrayList binding = null; 405 for (int i = 0; i < elements.length; i++) { 406 IConfigurationElement element = elements[i]; 407 if (!element.getContributor().getName().equals(pluginId)) { 408 continue; 409 } 410 if (BINDING_XP_NAME.equals(element.getName())) { 411 String refId = element.getAttribute("participantId"); for (int j = 0; j < elements.length; j++) { 414 IConfigurationElement rel = elements[j]; 415 if (!rel.getName().equals("searchParticipant")) continue; 417 if (rel.getAttribute("extensions") == null) continue; 420 String id = rel.getAttribute("id"); if (id != null && id.equals(refId)) { 422 if (binding == null) 424 binding = new ArrayList (); 425 binding.add(rel); 426 break; 427 } 428 } 429 } else if (SEARCH_PARTICIPANT_XP_NAME.equals(element.getName())) { 430 if (element.getAttribute("extensions") == null) continue; 433 if (!isParticipantEnabled(String.valueOf(true).equals(element.getAttribute("headless")))) continue; 435 if (list == null) 436 list = new ArrayList (); 437 ParticipantDescriptor desc = new ParticipantDescriptor(element); 438 list.add(desc); 439 searchParticipantsById.put(desc.getId(), desc); 440 } 441 } 442 if (binding != null) 443 list = addBoundDescriptors(list, binding); 444 return list; 445 } 446 447 454 455 private ArrayList addBoundDescriptors(ArrayList list, ArrayList binding) { 456 for (int i = 0; i < binding.size(); i++) { 457 IConfigurationElement refEl = (IConfigurationElement) binding.get(i); 458 Collection collection = searchParticipantsByPlugin.values(); 459 boolean found = false; 460 for (Iterator iter = collection.iterator(); iter.hasNext();) { 461 if (found) 462 break; 463 Object entry = iter.next(); 464 if (entry == PARTICIPANTS_NOT_FOUND) 465 continue; 466 ArrayList participants = (ArrayList ) entry; 467 for (int j = 0; j < participants.size(); j++) { 468 ParticipantDescriptor desc = (ParticipantDescriptor) participants.get(j); 469 if (desc.contains(refEl)) { 470 if (list == null) 472 list = new ArrayList (); 473 list.add(desc); 474 found = true; 475 break; 476 } 477 } 478 } 479 if (!found) { 480 if (list == null) 481 list = new ArrayList (); 482 ParticipantDescriptor d = new ParticipantDescriptor(refEl); 483 list.add(d); 484 searchParticipantsById.put(d.getId(), d); 485 } 486 } 487 return list; 488 } 489 490 495 496 public LuceneSearchParticipant[] getGlobalParticipants() { 497 if (globalSearchParticipants == null) { 498 createGlobalSearchParticipants(); 499 } 500 ArrayList result = new ArrayList (); 501 for (int i = 0; i < globalSearchParticipants.size(); i++) { 502 ParticipantDescriptor desc = (ParticipantDescriptor) globalSearchParticipants.get(i); 503 LuceneSearchParticipant p = desc.getParticipant(); 504 if (p != null) 505 result.add(p); 506 } 507 return (LuceneSearchParticipant[]) result.toArray(new LuceneSearchParticipant[result.size()]); 508 } 509 510 private void createGlobalSearchParticipants() { 511 globalSearchParticipants = new ArrayList (); 512 IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor( 513 SEARCH_PARTICIPANT_XP_FULLNAME); 514 for (int i = 0; i < elements.length; i++) { 515 IConfigurationElement element = elements[i]; 516 if (!element.getName().equals(SEARCH_PARTICIPANT_XP_NAME)) 517 continue; 518 if (element.getAttribute("extensions") != null) continue; 520 if (!isParticipantEnabled(String.valueOf(true).equals(element.getAttribute("headless")))) continue; 522 ParticipantDescriptor desc = new ParticipantDescriptor(element); 523 globalSearchParticipants.add(desc); 524 } 525 } 526 527 private ArrayList getParticipantDescriptors(String pluginId) { 528 Object result = searchParticipantsByPlugin.get(pluginId); 529 if (result == null) { 530 result = createSearchParticipants(pluginId); 531 if (result == null) 532 result = PARTICIPANTS_NOT_FOUND; 533 searchParticipantsByPlugin.put(pluginId, result); 534 } 535 if (result == PARTICIPANTS_NOT_FOUND) 536 return null; 537 return (ArrayList ) result; 538 } 539 540 public void search(ISearchQuery searchQuery, ISearchHitCollector collector, IProgressMonitor pm) 541 throws QueryTooComplexException { 542 SearchIndexWithIndexingProgress index = getIndex(searchQuery.getLocale()); 543 ensureIndexUpdated(pm, index); 544 if (index.exists()) { 545 index.search(searchQuery, collector); 546 } 547 } 548 549 555 public void ensureIndexUpdated(IProgressMonitor pm, SearchIndexWithIndexingProgress index) 556 throws OperationCanceledException { 557 558 ProgressDistributor progressDistrib = index.getProgressDistributor(); 559 progressDistrib.addMonitor(pm); 560 boolean configurationLocked = false; 561 try { 562 if (BaseHelpSystem.MODE_INFOCENTER != BaseHelpSystem.getMode()) { 568 try { 569 configurationLocked = index.tryLock(); 570 if (!configurationLocked) { 571 pm.beginTask("", 1); pm.worked(1); 575 pm.done(); 576 return; 577 } 578 } catch (OverlappingFileLockException ofle) { 579 } 582 } 583 if (index.isClosed() || !index.needsUpdating()) { 589 pm.beginTask("", 1); pm.worked(1); 592 pm.done(); 593 return; 594 } 595 if (pm instanceof SearchProgressMonitor) { 596 ((SearchProgressMonitor) pm).started(); 597 } 598 updateIndex(pm, index, progressDistrib); 599 } finally { 600 progressDistrib.removeMonitor(pm); 601 if (configurationLocked) { 602 index.releaseLock(); 603 } 604 } 605 } 606 607 private synchronized void updateIndex(IProgressMonitor pm, SearchIndex index, 608 ProgressDistributor progressDistrib) { 609 if (index.isClosed() || !index.needsUpdating()) { 610 pm.beginTask("", 1); pm.worked(1); 612 pm.done(); 613 return; 614 } 615 try { 616 PluginVersionInfo versions = index.getDocPlugins(); 617 if (versions == null) { 618 pm.beginTask("", 1); pm.worked(1); 620 pm.done(); 621 return; 622 } 623 IndexingOperation indexer = new IndexingOperation(index); 624 indexer.execute(progressDistrib); 625 return; 626 } 627 catch (OperationCanceledException e) { 628 progressDistrib.operationCanceled(); 629 throw e; 630 } 631 catch (IndexingException e) { 632 String msg = "Error indexing documents"; HelpBasePlugin.logError(msg, e); 634 } 635 } 636 637 640 public void close() { 641 synchronized (indexes) { 642 for (Iterator it = indexes.values().iterator(); it.hasNext();) { 643 ((SearchIndex) it.next()).close(); 644 } 645 } 646 } 647 648 public synchronized void tocsChanged() { 649 Collection activeIndexes = new ArrayList (); 650 synchronized (indexes) { 651 activeIndexes.addAll(indexes.values()); 652 } 653 for (Iterator it = activeIndexes.iterator(); it.hasNext();) { 654 SearchIndexWithIndexingProgress ix = (SearchIndexWithIndexingProgress) it.next(); 655 ix.close(); 656 synchronized (indexes) { 657 indexes.remove(ix.getLocale()); 658 ProgressDistributor pm = ix.getProgressDistributor(); 659 pm.beginTask("", 1); pm.worked(1); 661 pm.done(); 662 SearchProgressMonitor.reinit(ix.getLocale()); 663 } 664 } 665 } 666 } 667 | Popular Tags |