From ae2e4e8453a0e7ee7b8aa7c18be0e75c62fa74b8 Mon Sep 17 00:00:00 2001 From: Valeriy Svydenko Date: Thu, 12 Jan 2017 16:21:37 +0200 Subject: [PATCH] CHE-1038: make Navigate To File feature not case-sensitive (#3573) --- .../api/vfs/search/impl/LuceneSearcher.java | 45 +++++++++---------- .../vfs/search/impl/FSLuceneSearcherTest.java | 45 +++++++++++++++---- 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/LuceneSearcher.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/LuceneSearcher.java index c1cefab48ea..97d54aa53e0 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/LuceneSearcher.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/vfs/search/impl/LuceneSearcher.java @@ -33,7 +33,6 @@ import org.apache.lucene.search.SearcherFactory; import org.apache.lucene.search.SearcherManager; import org.apache.lucene.search.TopDocs; -import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.IOUtils; import org.eclipse.che.api.core.ForbiddenException; @@ -67,9 +66,11 @@ * @author andrew00x */ public abstract class LuceneSearcher implements Searcher { - private static final Logger LOG = LoggerFactory.getLogger(LuceneSearcher.class); - - private static final int RESULT_LIMIT = 1000; + private static final Logger LOG = LoggerFactory.getLogger(LuceneSearcher.class); + private static final int RESULT_LIMIT = 1000; + private static final String PATH_FIELD = "path"; + private static final String NAME_FIELD = "name"; + private static final String TEXT_FIELD = "text"; private final List excludeFileIndexFilters; private final AbstractLuceneSearcherProvider.CloseCallback closeCallback; @@ -207,7 +208,7 @@ public SearchResult search(QueryExpression query) throws ServerException { List results = newArrayList(); for (int i = 0; i < topDocs.scoreDocs.length; i++) { ScoreDoc scoreDoc = topDocs.scoreDocs[i]; - String filePath = luceneSearcher.doc(scoreDoc.doc).getField("path").stringValue(); + String filePath = luceneSearcher.doc(scoreDoc.doc).getField(PATH_FIELD).stringValue(); results.add(new SearchResultEntry(filePath)); } @@ -225,7 +226,7 @@ public SearchResult search(QueryExpression query) throws ServerException { .withNextPageQueryExpression(nextPageQueryExpression) .withElapsedTimeMillis(elapsedTimeMillis) .build(); - } catch (IOException e) { + } catch (IOException | ParseException e) { throw new ServerException(e.getMessage(), e); } finally { try { @@ -236,25 +237,23 @@ public SearchResult search(QueryExpression query) throws ServerException { } } - private Query createLuceneQuery(QueryExpression query) throws ServerException { + private Query createLuceneQuery(QueryExpression query) throws ParseException { final BooleanQuery luceneQuery = new BooleanQuery(); final String name = query.getName(); final String path = query.getPath(); final String text = query.getText(); if (path != null) { - luceneQuery.add(new PrefixQuery(new Term("path", path)), BooleanClause.Occur.MUST); + luceneQuery.add(new PrefixQuery(new Term(PATH_FIELD, path)), BooleanClause.Occur.MUST); } if (name != null) { - luceneQuery.add(new WildcardQuery(new Term("name", name)), BooleanClause.Occur.MUST); + QueryParser qParser = new QueryParser(NAME_FIELD, makeAnalyzer()); + qParser.setAllowLeadingWildcard(true); + luceneQuery.add(qParser.parse(name), BooleanClause.Occur.MUST); } if (text != null) { - QueryParser qParser = new QueryParser("text", makeAnalyzer()); + QueryParser qParser = new QueryParser(TEXT_FIELD, makeAnalyzer()); qParser.setAllowLeadingWildcard(true); - try { - luceneQuery.add(qParser.parse(text), BooleanClause.Occur.MUST); - } catch (ParseException e) { - throw new ServerException(e.getMessage()); - } + luceneQuery.add(qParser.parse(text), BooleanClause.Occur.MUST); } return luceneQuery; } @@ -328,8 +327,8 @@ protected void addFile(VirtualFile virtualFile) throws ServerException { try (Reader fContentReader = shouldIndexContent(virtualFile) ? new BufferedReader(new InputStreamReader(virtualFile.getContent())) : null) { - getIndexWriter() - .updateDocument(new Term("path", virtualFile.getPath().toString()), createDocument(virtualFile, fContentReader)); + getIndexWriter().updateDocument(new Term(PATH_FIELD, virtualFile.getPath().toString()), + createDocument(virtualFile, fContentReader)); } catch (OutOfMemoryError oome) { close(); throw oome; @@ -345,10 +344,10 @@ protected void addFile(VirtualFile virtualFile) throws ServerException { public final void delete(String path, boolean isFile) throws ServerException { try { if (isFile) { - Term term = new Term("path", path); + Term term = new Term(PATH_FIELD, path); getIndexWriter().deleteDocuments(term); } else { - Term term = new Term("path", path + "/"); + Term term = new Term(PATH_FIELD, path + '/'); getIndexWriter().deleteDocuments(new PrefixQuery(term)); } } catch (OutOfMemoryError oome) { @@ -361,7 +360,7 @@ public final void delete(String path, boolean isFile) throws ServerException { @Override public final void update(VirtualFile virtualFile) throws ServerException { - doUpdate(new Term("path", virtualFile.getPath().toString()), virtualFile); + doUpdate(new Term(PATH_FIELD, virtualFile.getPath().toString()), virtualFile); } protected void doUpdate(Term deleteTerm, VirtualFile virtualFile) throws ServerException { @@ -381,10 +380,10 @@ protected void doUpdate(Term deleteTerm, VirtualFile virtualFile) throws ServerE protected Document createDocument(VirtualFile virtualFile, Reader reader) throws ServerException { final Document doc = new Document(); - doc.add(new StringField("path", virtualFile.getPath().toString(), Field.Store.YES)); - doc.add(new StringField("name", virtualFile.getName(), Field.Store.YES)); + doc.add(new StringField(PATH_FIELD, virtualFile.getPath().toString(), Field.Store.YES)); + doc.add(new TextField(NAME_FIELD, virtualFile.getName(), Field.Store.YES)); if (reader != null) { - doc.add(new TextField("text", reader)); + doc.add(new TextField(TEXT_FIELD, reader)); } return doc; } diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/search/impl/FSLuceneSearcherTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/search/impl/FSLuceneSearcherTest.java index db150b7a82a..4a8b95fec61 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/search/impl/FSLuceneSearcherTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/vfs/search/impl/FSLuceneSearcherTest.java @@ -21,24 +21,25 @@ import org.eclipse.che.api.vfs.search.SearchResult; import org.eclipse.che.commons.lang.IoUtil; import org.eclipse.che.commons.lang.NameGenerator; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; import org.mockito.ArgumentMatcher; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; import java.io.File; import java.util.Collections; import java.util.List; import static com.google.common.collect.Lists.newArrayList; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; @SuppressWarnings("Duplicates") public class FSLuceneSearcherTest { @@ -54,7 +55,7 @@ public class FSLuceneSearcherTest { private FSLuceneSearcher searcher; private AbstractLuceneSearcherProvider.CloseCallback closeCallback; - @Before + @BeforeMethod public void setUp() throws Exception { File targetDir = new File(Thread.currentThread().getContextClassLoader().getResource(".").getPath()).getParentFile(); indexDirectory = new File(targetDir, NameGenerator.generate("index-", 4)); @@ -67,7 +68,7 @@ public void setUp() throws Exception { searcher = new FSLuceneSearcher(indexDirectory, filter, closeCallback); } - @After + @AfterMethod public void tearDown() throws Exception { searcher.close(); IoUtil.deleteRecursive(indexDirectory); @@ -190,6 +191,34 @@ public void searchesByTextAndFileName() throws Exception { assertEquals(newArrayList("/folder/xxx.txt"), paths); } + @DataProvider + public Object[][] searchByName() { + return new Object[][]{ + {"sameName.txt", "sameName.txt"}, + {"notCaseSensitive.txt", "notcasesensitive.txt"}, + {"fullName.txt", "full*"}, + {"file name.txt", "file name"}, + {"prefixFileName.txt", "prefixF*"}, + {"name.with.dot.txt", "name.With.Dot.txt"}, + }; + } + + @Test(dataProvider = "searchByName") + public void searchFileByName(String fileName, String searchedFileName) throws Exception { + VirtualFileSystem virtualFileSystem = virtualFileSystem(); + VirtualFile folder = virtualFileSystem.getRoot().createFolder("parent/child"); + VirtualFile folder2 = virtualFileSystem.getRoot().createFolder("folder2"); + folder.createFile(NameGenerator.generate(null,10), TEST_CONTENT[3]); + folder.createFile(fileName, TEST_CONTENT[2]); + folder.createFile(NameGenerator.generate(null,10), TEST_CONTENT[1]); + folder2.createFile(NameGenerator.generate(null,10), TEST_CONTENT[2]); + folder2.createFile(NameGenerator.generate(null,10), TEST_CONTENT[2]); + searcher.init(virtualFileSystem); + + List paths = searcher.search(new QueryExpression().setName(searchedFileName)).getFilePaths(); + assertEquals(newArrayList("/parent/child/" + fileName), paths); + } + @Test public void searchesByTextAndPath() throws Exception { VirtualFileSystem virtualFileSystem = virtualFileSystem();