1 11 package org.eclipse.help.internal.search; 12 13 import java.io.File ; 14 import java.io.FileOutputStream ; 15 import java.io.IOException ; 16 import java.io.InputStream ; 17 import java.io.RandomAccessFile ; 18 import java.net.MalformedURLException ; 19 import java.net.URL ; 20 import java.nio.channels.FileLock ; 21 import java.nio.channels.OverlappingFileLockException ; 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.HashMap ; 25 import java.util.HashSet ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.Locale ; 29 import java.util.Map ; 30 import java.util.Set ; 31 import java.util.zip.ZipEntry ; 32 import java.util.zip.ZipInputStream ; 33 34 import org.apache.lucene.document.Document; 35 import org.apache.lucene.document.Field; 36 import org.apache.lucene.index.IndexReader; 37 import org.apache.lucene.index.IndexWriter; 38 import org.apache.lucene.index.Term; 39 import org.apache.lucene.index.TermDocs; 40 import org.apache.lucene.search.BooleanQuery; 41 import org.apache.lucene.search.Hits; 42 import org.apache.lucene.search.IndexSearcher; 43 import org.apache.lucene.search.Query; 44 import org.apache.lucene.store.Directory; 45 import org.apache.lucene.store.FSDirectory; 46 import org.eclipse.core.runtime.IExtension; 47 import org.eclipse.core.runtime.IExtensionPoint; 48 import org.eclipse.core.runtime.IExtensionRegistry; 49 import org.eclipse.core.runtime.IProgressMonitor; 50 import org.eclipse.core.runtime.IStatus; 51 import org.eclipse.core.runtime.InvalidRegistryObjectException; 52 import org.eclipse.core.runtime.OperationCanceledException; 53 import org.eclipse.core.runtime.Platform; 54 import org.eclipse.core.runtime.Status; 55 import org.eclipse.help.internal.base.BaseHelpSystem; 56 import org.eclipse.help.internal.base.HelpBasePlugin; 57 import org.eclipse.help.internal.base.util.HelpProperties; 58 import org.eclipse.help.internal.protocols.HelpURLConnection; 59 import org.eclipse.help.internal.protocols.HelpURLStreamHandler; 60 import org.eclipse.help.internal.toc.TocFileProvider; 61 import org.eclipse.help.internal.toc.TocManager; 62 import org.eclipse.help.internal.util.ResourceLocator; 63 import org.eclipse.help.search.ISearchIndex; 64 import org.eclipse.help.search.LuceneSearchParticipant; 65 import org.osgi.framework.Bundle; 66 import org.osgi.framework.Constants; 67 import org.osgi.framework.Version; 68 69 72 public class SearchIndex implements ISearchIndex { 73 74 private IndexReader ir; 75 76 private IndexWriter iw; 77 78 private File indexDir; 79 80 private String locale; 81 82 private String relativePath; 83 84 private TocManager tocManager; 85 86 private AnalyzerDescriptor analyzerDescriptor; 87 88 private PluginVersionInfo docPlugins; 89 90 private HelpProperties indexedDocs; 92 93 public static final String INDEXED_CONTRIBUTION_INFO_FILE = "indexed_contributions"; 95 public static final String INDEXED_DOCS_FILE = "indexed_docs"; 97 public static final String DEPENDENCIES_VERSION_FILENAME = "indexed_dependencies"; 99 public static final String DEPENDENCIES_KEY_LUCENE = "lucene"; 101 public static final String DEPENDENCIES_KEY_ANALYZER = "analyzer"; 103 private static final String LUCENE_BUNDLE_ID = "org.apache.lucene"; 105 private static final String FIELD_NAME = "name"; 107 private static final String FIELD_INDEX_ID = "index_path"; 109 private File inconsistencyFile; 110 111 private HTMLSearchParticipant htmlSearchParticipant; 112 113 private IndexSearcher searcher; 114 115 private Object searcherCreateLock = new Object (); 116 117 private HelpProperties dependencies; 118 119 private boolean closed = false; 120 121 private Collection searches = new ArrayList (); 123 124 private FileLock lock; 125 126 134 public SearchIndex(String locale, AnalyzerDescriptor analyzerDesc, TocManager tocManager) { 135 this(new File (HelpBasePlugin.getConfigurationDirectory(), "index/" + locale), locale, analyzerDesc, tocManager, null); 137 } 138 139 148 149 public SearchIndex(File indexDir, String locale, AnalyzerDescriptor analyzerDesc, TocManager tocManager, 150 String relativePath) { 151 this.locale = locale; 152 this.analyzerDescriptor = analyzerDesc; 153 this.tocManager = tocManager; 154 this.indexDir = indexDir; 155 this.relativePath = relativePath; 156 inconsistencyFile = new File (indexDir.getParentFile(), locale + ".inconsistent"); htmlSearchParticipant = new HTMLSearchParticipant(indexDir.getAbsolutePath()); 159 if (!exists()) { 160 try { 161 if (tryLock()) { 162 try { 164 unzipProductIndex(); 165 } finally { 166 releaseLock(); 167 } 168 } 169 } catch (OverlappingFileLockException ofle) { 170 } 174 } 175 } 176 177 186 public IStatus addDocument(String name, URL url) { 187 try { 188 Document doc = new Document(); 189 doc.add(new Field(FIELD_NAME, name, Field.Store.YES, Field.Index.UN_TOKENIZED)); 190 addExtraFields(doc); 191 String pluginId = LocalSearchManager.getPluginId(name); 192 if (relativePath != null) { 193 doc.add(new Field(FIELD_INDEX_ID, relativePath, Field.Store.YES, Field.Index.UN_TOKENIZED)); 194 } 195 LuceneSearchParticipant participant = null; 197 HelpURLConnection urlc = new HelpURLConnection(url); 198 String id = urlc.getValue("id"); String pid = urlc.getValue("participantId"); if (pid != null) 201 participant = BaseHelpSystem.getLocalSearchManager().getGlobalParticipant(pid); 202 if (participant == null) 204 participant = BaseHelpSystem.getLocalSearchManager().getParticipant(pluginId, name); 205 if (participant != null) { 206 IStatus status = participant.addDocument(this, pluginId, name, url, id, doc); 207 if (status.getSeverity() == IStatus.OK) { 208 String filters = doc.get("filters"); indexedDocs.put(name, filters != null ? filters : "0"); if (id != null) 211 doc.add(new Field("id", id, Field.Store.YES, Field.Index.NO)); if (pid != null) 213 doc.add(new Field("participantId", pid, Field.Store.YES, Field.Index.NO)); iw.addDocument(doc); 215 } 216 return status; 217 } 218 IStatus status = htmlSearchParticipant.addDocument(this, pluginId, name, url, id, doc); 220 if (status.getSeverity() == IStatus.OK) { 221 String filters = doc.get("filters"); indexedDocs.put(name, filters != null ? filters : "0"); iw.addDocument(doc); 224 } 225 return status; 226 } catch (IOException e) { 227 return new Status(IStatus.ERROR, HelpBasePlugin.PLUGIN_ID, IStatus.ERROR, 228 "IO exception occurred while adding document " + name + " to index " + indexDir.getAbsolutePath() + ".", e); 231 } 232 catch (Exception e) { 233 return new Status(IStatus.ERROR, HelpBasePlugin.PLUGIN_ID, IStatus.ERROR, 234 "An unexpected internal error occurred while adding document " + name + " to index " + indexDir.getAbsolutePath() + ".", e); } 238 } 239 240 246 protected void addExtraFields(Document doc) { 247 } 248 249 252 public synchronized boolean beginAddBatch(boolean firstOperation) { 253 try { 254 if (iw != null) { 255 iw.close(); 256 } 257 boolean create = false; 258 if (!indexDir.exists() || !isLuceneCompatible() || !isAnalyzerCompatible() 259 || inconsistencyFile.exists() && firstOperation) { 260 create = true; 261 indexDir.mkdirs(); 262 if (!indexDir.exists()) 263 return false; } 265 indexedDocs = new HelpProperties(INDEXED_DOCS_FILE, indexDir); 266 indexedDocs.restore(); 267 setInconsistent(true); 268 iw = new IndexWriter(indexDir, analyzerDescriptor.getAnalyzer(), create); 269 iw.setMergeFactor(20); 270 iw.setMaxFieldLength(1000000); 271 return true; 272 } catch (IOException e) { 273 HelpBasePlugin.logError("Exception occurred in search indexing at beginAddBatch.", e); return false; 275 } 276 } 277 278 281 public synchronized boolean beginDeleteBatch() { 282 try { 283 if (ir != null) { 284 ir.close(); 285 } 286 indexedDocs = new HelpProperties(INDEXED_DOCS_FILE, indexDir); 287 indexedDocs.restore(); 288 setInconsistent(true); 289 ir = IndexReader.open(indexDir); 290 return true; 291 } catch (IOException e) { 292 HelpBasePlugin.logError("Exception occurred in search indexing at beginDeleteBatch.", e); return false; 294 } 295 } 296 297 300 public synchronized boolean beginRemoveDuplicatesBatch() { 301 try { 302 if (ir != null) { 303 ir.close(); 304 } 305 ir = IndexReader.open(indexDir); 306 return true; 307 } catch (IOException e) { 308 HelpBasePlugin.logError("Exception occurred in search indexing at beginDeleteBatch.", e); return false; 310 } 311 } 312 313 320 public IStatus removeDocument(String name) { 321 Term term = new Term(FIELD_NAME, name); 322 try { 323 ir.deleteDocuments(term); 324 indexedDocs.remove(name); 325 } catch (IOException e) { 326 return new Status(IStatus.ERROR, HelpBasePlugin.PLUGIN_ID, IStatus.ERROR, 327 "IO exception occurred while removing document " + name + " from index " + indexDir.getAbsolutePath() + ".", e); 330 } 331 return Status.OK_STATUS; 332 } 333 334 337 public synchronized boolean endAddBatch(boolean optimize, boolean lastOperation) { 338 try { 339 if (iw == null) 340 return false; 341 if (optimize) 342 iw.optimize(); 343 iw.close(); 344 iw = null; 345 getDocPlugins().save(); 349 saveDependencies(); 350 if (lastOperation) { 351 indexedDocs.save(); 352 indexedDocs = null; 353 setInconsistent(false); 354 } 355 356 360 if (searcher != null) { 361 searcher.close(); 362 searcher = null; 363 } 364 return true; 365 } catch (IOException e) { 366 HelpBasePlugin.logError("Exception occurred in search indexing at endAddBatch.", e); return false; 368 } 369 } 370 371 374 public synchronized boolean endDeleteBatch() { 375 try { 376 if (ir == null) 377 return false; 378 ir.close(); 379 ir = null; 380 indexedDocs.save(); 384 indexedDocs = null; 385 getDocPlugins().save(); 386 saveDependencies(); 387 388 392 if (searcher != null) { 393 searcher.close(); 394 searcher = null; 395 } 396 return true; 397 } catch (IOException e) { 398 HelpBasePlugin.logError("Exception occurred in search indexing at endDeleteBatch.", e); return false; 400 } 401 } 402 403 406 public synchronized boolean endRemoveDuplicatesBatch() { 407 try { 408 if (ir == null) 409 return false; 410 ir.close(); 411 ir = null; 412 indexedDocs.save(); 416 indexedDocs = null; 417 getDocPlugins().save(); 418 saveDependencies(); 419 setInconsistent(false); 420 return true; 421 } catch (IOException e) { 422 HelpBasePlugin.logError("Exception occurred in search indexing at endDeleteBatch.", e); return false; 424 } 425 } 426 427 435 public Map merge(PluginIndex[] pluginIndexes, IProgressMonitor monitor) { 436 ArrayList dirList = new ArrayList (pluginIndexes.length); 437 Map mergedDocs = new HashMap (); 438 for (int p = 0; p < pluginIndexes.length; p++) { 441 List indexIds = pluginIndexes[p].getIDs(); 442 List indexPaths = pluginIndexes[p].getPaths(); 443 if (monitor.isCanceled()) { 444 throw new OperationCanceledException(); 445 } 446 447 for (int i = 0; i < indexPaths.size(); i++) { 448 String indexId = (String ) indexIds.get(i); 449 String indexPath = (String ) indexPaths.get(i); 450 try { 451 dirList.add(FSDirectory.getDirectory(indexPath, false)); 452 } catch (IOException ioe) { 453 HelpBasePlugin 454 .logError( 455 "Help search indexing directory could not be created for directory " + indexPath, ioe); continue; 457 } 458 459 HelpProperties prebuiltDocs = new HelpProperties(INDEXED_DOCS_FILE, new File (indexPath)); 460 prebuiltDocs.restore(); 461 Set prebuiltHrefs = prebuiltDocs.keySet(); 462 for (Iterator it = prebuiltHrefs.iterator(); it.hasNext();) { 463 String href = (String ) it.next(); 464 if (i == 0) { 465 mergedDocs.put(href, null); 467 } else { 468 if (mergedDocs.containsKey(href)) { 469 String [] dups = (String []) mergedDocs.get(href); 471 if (dups == null) { 472 mergedDocs.put(href, new String [] { indexId }); 474 } else { 475 String [] newDups = new String [dups.length + 1]; 477 System.arraycopy(dups, 0, newDups, 0, dups.length); 478 newDups[dups.length] = indexId; 479 mergedDocs.put(href, newDups); 480 } 481 } else { 482 mergedDocs.put(href, null); 485 } 486 487 } 488 } 489 } 490 } 491 for (Iterator it = mergedDocs.keySet().iterator(); it.hasNext();) { 493 indexedDocs.put(it.next(), "0"); } 495 Directory[] luceneDirs = (Directory[]) dirList.toArray(new Directory[dirList.size()]); 496 try { 497 iw.addIndexes(luceneDirs); 498 } catch (IOException ioe) { 499 HelpBasePlugin.logError("Merging search indexes failed.", ioe); return new HashMap (); 501 } 502 return mergedDocs; 503 } 504 505 public IStatus removeDuplicates(String name, String [] index_paths) { 506 TermDocs hrefDocs = null; 507 TermDocs indexDocs = null; 508 Term hrefTerm = new Term(FIELD_NAME, name); 509 try { 510 for (int i = 0; i < index_paths.length; i++) { 511 Term indexTerm = new Term(FIELD_INDEX_ID, index_paths[i]); 512 if (i == 0) { 513 hrefDocs = ir.termDocs(hrefTerm); 514 indexDocs = ir.termDocs(indexTerm); 515 } else { 516 hrefDocs.seek(hrefTerm); 517 indexDocs.seek(indexTerm); 518 } 519 removeDocuments(hrefDocs, indexDocs); 520 } 521 } catch (IOException ioe) { 522 return new Status(IStatus.ERROR, HelpBasePlugin.PLUGIN_ID, IStatus.ERROR, 523 "IO exception occurred while removing duplicates of document " + name + " from index " + indexDir.getAbsolutePath() + ".", ioe); 526 } finally { 527 if (hrefDocs != null) { 528 try { 529 hrefDocs.close(); 530 } catch (IOException e) { 531 } 532 } 533 if (indexDocs != null) { 534 try { 535 indexDocs.close(); 536 } catch (IOException e) { 537 } 538 } 539 } 540 return Status.OK_STATUS; 541 } 542 543 550 private void removeDocuments(TermDocs doc1, TermDocs docs2) throws IOException { 551 if (!doc1.next()) { 552 return; 553 } 554 if (!docs2.next()) { 555 return; 556 } 557 while (true) { 558 if (doc1.doc() < docs2.doc()) { 559 if (!doc1.skipTo(docs2.doc())) { 560 if (!doc1.next()) { 561 return; 562 } 563 } 564 } else if (doc1.doc() > docs2.doc()) { 565 if (!docs2.skipTo(doc1.doc())) { 566 if (!doc1.next()) { 567 return; 568 } 569 } 570 } 571 if (doc1.doc() == docs2.doc()) { 572 ir.deleteDocument(doc1.doc()); 573 if (!doc1.next()) { 574 return; 575 } 576 if (!docs2.next()) { 577 return; 578 } 579 } 580 } 581 } 582 583 588 public boolean exists() { 589 return indexDir.exists() && !isInconsistent(); 590 } 592 593 596 public void search(ISearchQuery searchQuery, ISearchHitCollector collector) 597 throws QueryTooComplexException { 598 try { 599 if (closed) 600 return; 601 registerSearch(Thread.currentThread()); 602 if (closed) 603 return; 604 QueryBuilder queryBuilder = new QueryBuilder(searchQuery.getSearchWord(), analyzerDescriptor); 605 Query luceneQuery = queryBuilder.getLuceneQuery(searchQuery.getFieldNames(), searchQuery 606 .isFieldSearch()); 607 String highlightTerms = queryBuilder.gethighlightTerms(); 608 if (luceneQuery != null) { 609 if (searcher == null) { 610 openSearcher(); 611 } 612 Hits hits = searcher.search(luceneQuery); 613 collector.addHits(LocalSearchManager.asList(hits), highlightTerms); 614 } 615 } catch (BooleanQuery.TooManyClauses tmc) { 616 throw new QueryTooComplexException(); 617 } catch (QueryTooComplexException qe) { 618 throw qe; 619 } catch (Exception e) { 620 HelpBasePlugin.logError("Exception occurred performing search for: " + searchQuery.getSearchWord() + ".", e); } finally { 623 unregisterSearch(Thread.currentThread()); 624 } 625 } 626 627 public String getLocale() { 628 return locale; 629 } 630 631 634 public PluginVersionInfo getDocPlugins() { 635 if (docPlugins == null) { 636 Set totalIds = new HashSet (); 637 IExtensionRegistry registry = Platform.getExtensionRegistry(); 638 IExtensionPoint extensionPoint = registry.getExtensionPoint(TocFileProvider.EXTENSION_POINT_ID_TOC); 639 IExtension[] extensions = extensionPoint.getExtensions(); 640 for (int i=0;i<extensions.length;++i) { 641 try { 642 totalIds.add(extensions[i].getNamespaceIdentifier()); 643 } 644 catch (InvalidRegistryObjectException e) { 645 } 647 } 648 Collection additionalPluginIds = BaseHelpSystem.getLocalSearchManager() 649 .getPluginsWithSearchParticipants(); 650 totalIds.addAll(additionalPluginIds); 651 docPlugins = new PluginVersionInfo(INDEXED_CONTRIBUTION_INFO_FILE, totalIds, indexDir, !exists()); 652 } 653 return docPlugins; 654 } 655 656 661 public void setDocPlugins(PluginVersionInfo docPlugins) { 662 this.docPlugins = docPlugins; 663 } 664 665 670 public HelpProperties getIndexedDocs() { 671 HelpProperties indexedDocs = new HelpProperties(INDEXED_DOCS_FILE, indexDir); 672 if (exists()) 673 indexedDocs.restore(); 674 return indexedDocs; 675 } 676 677 680 private HelpProperties getDependencies() { 681 if (dependencies == null) { 682 dependencies = new HelpProperties(DEPENDENCIES_VERSION_FILENAME, indexDir); 683 dependencies.restore(); 684 } 685 return dependencies; 686 } 687 688 private boolean isLuceneCompatible() { 689 String usedLuceneVersion = getDependencies().getProperty(DEPENDENCIES_KEY_LUCENE); 690 return isLuceneCompatible(usedLuceneVersion); 691 } 692 693 public boolean isLuceneCompatible(String luceneVersion) { 694 if (luceneVersion==null) return false; 695 String currentLuceneVersion = ""; Bundle luceneBundle = Platform.getBundle(LUCENE_BUNDLE_ID); 697 if (luceneBundle != null) { 698 currentLuceneVersion += (String ) luceneBundle.getHeaders() 699 .get(Constants.BUNDLE_VERSION); 700 } 701 if (currentLuceneVersion.equals(luceneVersion)) 703 return true; 704 Version version = new Version(currentLuceneVersion); 705 Version currentVersion = new Version(luceneVersion); 706 return version.getMajor() == currentVersion.getMajor() 709 && version.getMinor() == currentVersion.getMinor() 710 && version.getMicro() == currentVersion.getMicro(); 711 } 712 713 private boolean isAnalyzerCompatible() { 714 String usedAnalyzer = getDependencies().getProperty(DEPENDENCIES_KEY_ANALYZER); 715 return isAnalyzerCompatible(usedAnalyzer); 716 } 717 718 public boolean isAnalyzerCompatible(String analyzerId) { 719 if (analyzerId == null) { 720 analyzerId = ""; } 722 return analyzerDescriptor.isCompatible(analyzerId); 723 } 724 725 728 private void saveDependencies() { 729 getDependencies().put(DEPENDENCIES_KEY_ANALYZER, analyzerDescriptor.getId()); 730 Bundle luceneBundle = Platform.getBundle(LUCENE_BUNDLE_ID); 731 if (luceneBundle != null) { 732 String luceneBundleVersion = "" + luceneBundle.getHeaders().get(Constants.BUNDLE_VERSION); 734 getDependencies().put(DEPENDENCIES_KEY_LUCENE, luceneBundleVersion); 735 } else { 736 getDependencies().put(DEPENDENCIES_KEY_LUCENE, ""); } 738 getDependencies().save(); 739 } 740 741 745 public boolean isInconsistent() { 746 if (inconsistencyFile.exists()) { 747 return true; 748 } 749 return !isLuceneCompatible() || !isAnalyzerCompatible(); 750 } 751 752 755 public void setInconsistent(boolean inconsistent) { 756 if (inconsistent) { 757 try { 758 FileOutputStream fos = new FileOutputStream (inconsistencyFile); 761 fos.close(); 762 } catch (IOException ioe) { 763 } 764 } else 765 inconsistencyFile.delete(); 766 } 767 768 public void openSearcher() throws IOException { 769 synchronized (searcherCreateLock) { 770 if (searcher == null) { 771 searcher = new IndexSearcher(indexDir.getAbsolutePath()); 772 } 773 } 774 } 775 776 780 public void close() { 781 closed = true; 782 synchronized (searches) { 784 while (searches.size() > 0) { 785 try { 786 Thread.sleep(50); 787 } catch (InterruptedException ie) { 788 } 789 } 790 if (searcher != null) { 792 try { 793 searcher.close(); 794 } catch (IOException ioe) { 795 } 796 } 797 } 798 } 799 800 803 private void unzipProductIndex() { 804 String indexPluginId = HelpBasePlugin.getDefault().getPluginPreferences().getString("productIndex"); if (indexPluginId == null || indexPluginId.length() <= 0) { 806 return; 807 } 808 InputStream zipIn = ResourceLocator.openFromPlugin(indexPluginId, "doc_index.zip", getLocale()); if (zipIn == null) { 810 return; 811 } 812 setInconsistent(true); 813 cleanOldIndex(); 814 byte[] buf = new byte[8192]; 815 File destDir = indexDir; 816 ZipInputStream zis = new ZipInputStream (zipIn); 817 FileOutputStream fos = null; 818 try { 819 ZipEntry zEntry; 820 while ((zEntry = zis.getNextEntry()) != null) { 821 if (zEntry.isDirectory()) { 823 new File (destDir, zEntry.getName()).mkdirs(); 824 continue; 825 } 826 String filePath = zEntry.getName(); 828 int lastSeparator = filePath.lastIndexOf("/"); String fileDir = ""; if (lastSeparator >= 0) { 831 fileDir = filePath.substring(0, lastSeparator); 832 } 833 new File (destDir, fileDir).mkdirs(); 835 File outFile = new File (destDir, filePath); 837 fos = new FileOutputStream (outFile); 838 int n = 0; 839 while ((n = zis.read(buf)) >= 0) { 840 fos.write(buf, 0, n); 841 } 842 fos.close(); 843 } 844 setInconsistent(false); 845 } catch (IOException ioe) { 846 if (fos != null) { 847 try { 848 fos.close(); 849 } catch (IOException ioe2) { 850 } 851 } 852 } finally { 853 try { 854 zipIn.close(); 855 if (zis != null) 856 zis.close(); 857 } catch (IOException ioe) { 858 } 859 } 860 } 861 862 865 private void cleanOldIndex() { 866 IndexWriter cleaner = null; 867 try { 868 cleaner = new IndexWriter(indexDir, analyzerDescriptor.getAnalyzer(), true); 869 } catch (IOException ioe) { 870 } finally { 871 try { 872 if (cleaner != null) 873 cleaner.close(); 874 } catch (IOException ioe) { 875 } 876 } 877 } 878 879 882 public synchronized boolean needsUpdating() { 883 if (!exists()) { 884 return true; 885 } 886 return getDocPlugins().detectChange(); 887 } 888 889 892 public TocManager getTocManager() { 893 return tocManager; 894 } 895 896 private void registerSearch(Thread t) { 897 synchronized (searches) { 898 searches.add(t); 899 } 900 } 901 902 private void unregisterSearch(Thread t) { 903 synchronized (searches) { 904 searches.remove(t); 905 } 906 } 907 908 911 public boolean isClosed() { 912 return closed; 913 } 914 915 920 public synchronized boolean tryLock() throws OverlappingFileLockException { 921 if (lock != null) { 922 throw new OverlappingFileLockException (); 923 } 924 File lockFile = getLockFile(); 925 lockFile.getParentFile().mkdirs(); 926 try { 927 RandomAccessFile raf = new RandomAccessFile (lockFile, "rw"); FileLock l = raf.getChannel().tryLock(); 929 if (l != null) { 930 lock = l; 931 return true; 932 } 933 } catch (IOException ioe) { 934 lock = null; 935 } 936 return false; 937 } 938 939 private File getLockFile() { 940 return new File (indexDir.getParentFile(), locale + ".lock"); } 942 943 948 949 public synchronized boolean deleteLockFile() { 950 if (lock != null) 951 return false; 952 File lockFile = getLockFile(); 953 if (lockFile.exists()) 954 return lockFile.delete(); 955 return true; 956 } 957 958 public synchronized void releaseLock() { 959 if (lock != null) { 960 try { 961 lock.channel().close(); 962 } catch (IOException ioe) { 963 } 964 lock = null; 965 } 966 } 967 968 public static String getIndexableHref(String url) { 969 String fileName = url.toLowerCase(Locale.ENGLISH); 970 if (fileName.endsWith(".htm") || fileName.endsWith(".html") || fileName.endsWith(".xhtml") || fileName.endsWith(".xml") || fileName.endsWith(".txt")) { } else if (fileName.indexOf(".htm#") >= 0 || fileName.indexOf(".html#") >= 0 || fileName.indexOf(".xhtml#") >= 0 || fileName.indexOf(".xml#") >= 0) { url = url.substring(0, url.lastIndexOf('#')); 981 } else { 983 return BaseHelpSystem.getLocalSearchManager().isIndexable(url) ? url : null; 985 } 986 return url; 987 } 988 989 997 public static URL getIndexableURL(String locale, String url) { 998 return getIndexableURL(locale, url, null, null); 999 } 1000 1001 1010 public static URL getIndexableURL(String locale, String url, String id, String participantId) { 1011 if (participantId == null) 1012 url = getIndexableHref(url); 1013 if (url == null) 1014 return null; 1015 1016 try { 1017 StringBuffer query = new StringBuffer (); 1018 query.append("?"); query.append("lang=" + locale); if (id != null) 1021 query.append("&id=" + id); if (participantId != null) 1023 query.append("&participantId=" + participantId); return new URL ("help", null, -1, url + query.toString(), HelpURLStreamHandler.getDefault()); 1026 1027 } catch (MalformedURLException mue) { 1028 return null; 1029 } 1030 } 1031 1032 public IStatus addDocument(String pluginId, String name, URL url, String id, Document doc) { 1033 LuceneSearchParticipant participant = BaseHelpSystem.getLocalSearchManager() 1035 .getParticipant(pluginId, name); 1036 if (participant != null) { 1037 try { 1038 return participant.addDocument(this, pluginId, name, url, id, doc); 1039 } 1040 catch (Throwable t) { 1041 return new Status(IStatus.ERROR, HelpBasePlugin.PLUGIN_ID, IStatus.ERROR, 1042 "Error while adding document to search participant (addDocument()): " + name + ", " + url + "for participant " + participant.getClass().getName(), t); } 1045 } 1046 return htmlSearchParticipant.addDocument(this, pluginId, name, url, id, doc); 1048 } 1049} 1050 | Popular Tags |