예제 #1
0
 @NotNull
 private static String get(@NotNull String type, @NotNull String subType) {
   Util.checkNotNull(type, subType);
   assert subType.length() > 0;
   assert !subType.startsWith("/") && !subType.startsWith("\\");
   return type + "/" + subType.toLowerCase(Locale.ENGLISH);
 }
예제 #2
0
 private ResultPage(
     @NotNull List<ResultDocument> resultDocuments, int pageIndex, int pageCount, int hitCount) {
   this.resultDocuments = Util.checkNotNull(resultDocuments);
   this.pageIndex = pageIndex;
   this.pageCount = pageCount;
   this.hitCount = hitCount;
 }
예제 #3
0
  public Path(@NotNull String path) {
    Util.checkNotNull(path);
    this.path = normalizePath(path);
    this.canonicalFile = getCanonicalFile();

    /*
     * If the file is a root, such as '/' or 'C:', then File.getName() will
     * return an empty string. In that case, use toString() instead, which
     * will return '/' and 'C:', respectively. We don't want an empty string
     * as name because it will be used for display on the GUI.
     */
    this.name = getDisplayName(canonicalFile);
  }
예제 #4
0
  // Given deletions should not be in the registry anymore, since the receiver
  // will retrieve a fresh set of indexes from the registry before approval
  @ThreadSafe
  @VisibleForPackageGroup
  public void approveDeletions(@NotNull List<PendingDeletion> deletions) {
    Util.checkNotNull(deletions);
    if (deletions.isEmpty()) return;

    /*
     * If the deletion thread is not available anymore, approve of deletions
     * immediately. - Otherwise the given deletion objects would just hang
     * around in the queue until program shutdown and never receive
     * approval, thus the associated indexes would never get deleted.
     */
    synchronized (this) {
      if (deletionThread.isInterrupted()) {
        for (PendingDeletion pendingDeletion : deletions) pendingDeletion.setApprovedBySearcher();
      } else {
        deletionQueue.add(deletions);
      }
    }
  }
예제 #5
0
 // Caller must close returned searcher
 @NotNull
 @NotThreadSafe
 private List<CorruptedIndex> setLuceneSearcher(@NotNull List<LuceneIndex> indexes)
     throws IOException {
   this.indexes = Util.checkNotNull(indexes);
   Searchable[] searchables = new Searchable[indexes.size()];
   LazyList<CorruptedIndex> corrupted = new LazyList<CorruptedIndex>();
   for (int i = 0; i < indexes.size(); i++) {
     LuceneIndex index = indexes.get(i);
     try {
       searchables[i] = new IndexSearcher(index.getLuceneDir());
     } catch (IOException e) {
       Util.printErr(e);
       searchables[i] = new DummySearchable();
       corrupted.add(new CorruptedIndex(index, e));
     }
   }
   luceneSearcher = new MultiSearcher(searchables);
   return corrupted;
 }
예제 #6
0
 private QueryWrapper(@NotNull Query query, boolean isPhraseQuery) {
   this.query = Util.checkNotNull(query);
   this.isPhraseQuery = isPhraseQuery;
 }
예제 #7
0
  /**
   * For the given query, returns the requested page of results. This method should not be called
   * anymore after {@link #shutdown()} has been called, otherwise an IOException will be thrown.
   */
  @NotNull
  @ThreadSafe
  public ResultPage search(@NotNull WebQuery webQuery)
      throws IOException, SearchException, CheckedOutOfMemoryError {
    Util.checkNotNull(webQuery);

    if (ioException != null) throw ioException;

    List<Filter> filters = new ArrayList<Filter>(3);

    // Add size filter to filter chain
    if (webQuery.minSize != null || webQuery.maxSize != null) {
      filters.add(
          NumericRangeFilter.newLongRange(
              Fields.SIZE.key(), webQuery.minSize, webQuery.maxSize, true, true));
    }

    // Add type filter to filter chain
    if (webQuery.parsers != null) {
      TermsFilter typeFilter = new TermsFilter();
      String fieldName = Fields.PARSER.key();
      typeFilter.addTerm(new Term(fieldName, Fields.EMAIL_PARSER));
      for (Parser parser : webQuery.parsers) {
        String parserName = parser.getClass().getSimpleName();
        typeFilter.addTerm(new Term(fieldName, parserName));
      }
      filters.add(typeFilter);
    }

    // Add location filter to filter chain
    if (webQuery.indexes != null) {
      Filter[] indexFilters = new Filter[webQuery.indexes.size()];
      int i = 0;
      for (LuceneIndex index : webQuery.indexes) {
        Path path = index.getRootFolder().getPath();
        String uid = index.getDocumentType().createUniqueId(path);
        Term prefix = new Term(Fields.UID.key(), uid + "/");
        indexFilters[i++] = new PrefixFilter(prefix);
      }
      filters.add(new ChainedFilter(indexFilters, ChainedFilter.OR));
    }

    // Construct filter chain
    Filter filter =
        filters.size() == 0
            ? null
            : new ChainedFilter(filters.toArray(new Filter[filters.size()]), ChainedFilter.AND);

    // Create query
    QueryWrapper queryWrapper = createQuery(webQuery.query);
    Query query = queryWrapper.query;
    boolean isPhraseQuery = queryWrapper.isPhraseQuery;

    readLock.lock();
    try {
      checkIndexesExist();

      // Perform search; might throw OutOfMemoryError
      int maxResults = (webQuery.pageIndex + 1) * PAGE_SIZE;
      TopDocs topDocs = luceneSearcher.search(query, filter, maxResults);
      ScoreDoc[] scoreDocs = topDocs.scoreDocs;

      // Compute start and end indices of returned page
      int start;
      int end = scoreDocs.length;
      if (end <= PAGE_SIZE) {
        start = 0;
      } else {
        int r = end % PAGE_SIZE;
        start = end - (r == 0 ? PAGE_SIZE : r);
      }

      // Create and fill list of result documents to return
      ResultDocument[] results = new ResultDocument[end - start];
      for (int i = start; i < end; i++) {
        Document doc = luceneSearcher.doc(scoreDocs[i].doc);
        float score = scoreDocs[i].score;
        LuceneIndex index = indexes.get(luceneSearcher.subSearcher(i));
        IndexingConfig config = index.getConfig();
        results[i - start] =
            new ResultDocument(
                doc, score, query, isPhraseQuery, config, fileFactory, outlookMailFactory);
      }

      int hitCount = topDocs.totalHits;
      int newPageIndex = start / PAGE_SIZE;
      int pageCount = (int) Math.ceil((float) hitCount / PAGE_SIZE);

      return new ResultPage(Arrays.asList(results), newPageIndex, pageCount, hitCount);
    } catch (IllegalArgumentException e) {
      throw wrapEmptyIndexException(e);
    } catch (OutOfMemoryError e) {
      throw new CheckedOutOfMemoryError(e);
    } finally {
      readLock.unlock();
    }
  }
예제 #8
0
  /**
   * This method should not be called by clients. Use {@link IndexRegistry#getSearcher()} instead.
   *
   * @param corruptedIndexes A list that will be filled by this constructor with indexes that
   *     couldn't be loaded.
   */
  @VisibleForPackageGroup
  public Searcher(
      @NotNull IndexRegistry indexRegistry,
      @NotNull FileFactory fileFactory,
      @NotNull OutlookMailFactory outlookMailFactory,
      @NotNull final List<CorruptedIndex> corruptedIndexes)
      throws IOException {
    Util.checkNotNull(indexRegistry, fileFactory, outlookMailFactory);
    this.indexRegistry = indexRegistry;
    this.fileFactory = fileFactory;
    this.outlookMailFactory = outlookMailFactory;

    readLock = indexRegistry.getReadLock();
    writeLock = indexRegistry.getWriteLock();

    // Handler for index additions
    addedListener =
        new Event.Listener<LuceneIndex>() {
          public void update(LuceneIndex eventData) {
            replaceLuceneSearcher();
          }
        };

    /*
     * This lock could be moved into the indexes handler, but we'll put it
     * here to avoid releasing and reacquiring it.
     */
    writeLock.lock();
    try {
      indexRegistry.addListeners(
          new ExistingIndexesHandler() {
            // Handle existing indexes
            public void handleExistingIndexes(List<LuceneIndex> indexes) {
              try {
                corruptedIndexes.addAll(setLuceneSearcher(indexes));
              } catch (IOException e) {
                ioException = e;
              }
            }
          },
          addedListener,
          null); // removedListener is null, see deletion thread below
    } finally {
      writeLock.unlock();
    }

    if (ioException != null) throw ioException;

    // Handler for index removals
    deletionThread =
        new Thread(Searcher.class.getName() + " (Approve pending deletions)") {
          public void run() {
            while (true) {
              try {
                List<PendingDeletion> deletions = deletionQueue.take();
                replaceLuceneSearcher();
                for (PendingDeletion deletion : deletions) deletion.setApprovedBySearcher();
              } catch (InterruptedException e) {
                break;
              }
            }
          }
        };
    deletionThread.start();
  }
예제 #9
0
 public Attachment(@NotNull String filename, @NotNull FileResource fileResource) {
   this.filename = Util.checkNotNull(filename);
   this.fileResource = Util.checkNotNull(fileResource);
 }
예제 #10
0
 protected ComboEditSupport(@NotNull Class<EN> choiceClass) {
   this.choiceClass = Util.checkNotNull(choiceClass);
 }