-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #560 - Added endpoint to configuration server to find files co…
…ntaining specific text (#659) Co-authored-by: Marius Oehler <[email protected]>
- Loading branch information
1 parent
41170f3
commit e840d16
Showing
7 changed files
with
413 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
...figurationserver/src/main/java/rocks/inspectit/ocelot/search/FileContentSearchEngine.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
package rocks.inspectit.ocelot.search; | ||
|
||
import lombok.Value; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
import rocks.inspectit.ocelot.file.FileInfo; | ||
import rocks.inspectit.ocelot.file.FileManager; | ||
import rocks.inspectit.ocelot.file.accessor.git.RevisionAccess; | ||
|
||
import java.util.*; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
/** | ||
* Component to search for a specific pattern in the configuration files. | ||
*/ | ||
@Component | ||
public class FileContentSearchEngine { | ||
|
||
@Autowired | ||
private FileManager fileManager; | ||
|
||
/** | ||
* Searches in all files in the current Workspace Revision of the server for the given query. The minimum amount of | ||
* returned entries is the amount that could be found, the maximum amount of returned entries is defined by the | ||
* limit parameter. | ||
* Returns a List containing {@link SearchResult} instances. Each of these instances resembles one occurrence of the | ||
* given query. | ||
* <p> | ||
* If the given query is an empty String, an empty Map is returned. | ||
* | ||
* @param query The String that is searched for. | ||
* @param limit The maximum amount of entries that should be searched. Set to -1 to get all entries returned. | ||
* | ||
* @return A List containing {@link SearchResult} instances for each found match. | ||
*/ | ||
public List<SearchResult> search(String query, int limit) { | ||
if (query.isEmpty()) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
return search(query, limit, fileManager.getWorkspaceRevision()); | ||
} | ||
|
||
/** | ||
* Searches in all configuration files which can be accessed by the given {@link RevisionAccess} for the specified | ||
* query string. The amount of results can be limited using the limit argument. | ||
* | ||
* @param query the query string to look for | ||
* @param limit the maximum amount of results | ||
* @param revisionAccess the accessor for fetching the files | ||
* | ||
* @return a list of {@link SearchResult} representing the matches | ||
*/ | ||
private List<SearchResult> search(String query, int limit, RevisionAccess revisionAccess) { | ||
Pattern queryPattern = Pattern.compile(Pattern.quote(query)); | ||
List<FileInfo> files = revisionAccess.listConfigurationFiles(""); | ||
|
||
AtomicInteger limitCounter = new AtomicInteger(limit); | ||
|
||
List<SearchResult> result = files.stream() | ||
.map(fileInfo -> fileInfo.getAbsoluteFilePaths("")) | ||
.reduce(Stream.empty(), Stream::concat) | ||
.map(filename -> { | ||
Optional<String> content = revisionAccess.readConfigurationFile(filename); | ||
return content.map(fileContent -> findQuery(filename, fileContent, queryPattern, limitCounter)); | ||
}) | ||
.filter(Optional::isPresent) | ||
.map(Optional::get) | ||
.flatMap(Collection::stream) | ||
.collect(Collectors.toList()); | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* Searches in the specified content for the specified query pattern. The passed content represents the content of the | ||
* file with the specified name. | ||
* | ||
* @param fileName the filename of the current file | ||
* @param content the file's content | ||
* @param queryPattern the pattern to search for | ||
* @param limitCounter the amount of results to add | ||
* | ||
* @return a list of {@link SearchResult} representing the matches | ||
*/ | ||
private List<SearchResult> findQuery(String fileName, String content, Pattern queryPattern, AtomicInteger limitCounter) { | ||
if (StringUtils.isEmpty(content)) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
List<SearchResult> results = new ArrayList<>(); | ||
|
||
List<Line> lines = getLines(content); | ||
|
||
ListIterator<Line> listIterator = lines.listIterator(); | ||
Line currentLine = listIterator.next(); | ||
|
||
Matcher matcher = queryPattern.matcher(content); | ||
while (matcher.find() && limitCounter.decrementAndGet() >= 0) { | ||
int start = matcher.start(); | ||
int end = matcher.end(); | ||
|
||
while (start >= currentLine.getEndIndex()) { | ||
currentLine = listIterator.next(); | ||
} | ||
int startLine = currentLine.getLineNumber(); | ||
int relativeStart = start - currentLine.getStartIndex(); | ||
|
||
while (end > currentLine.getEndIndex()) { | ||
currentLine = listIterator.next(); | ||
} | ||
int endLine = currentLine.getLineNumber(); | ||
int relativeEnd = end - currentLine.getStartIndex(); | ||
|
||
SearchResult result = new SearchResult(fileName, startLine, relativeStart, endLine, relativeEnd); | ||
results.add(result); | ||
} | ||
|
||
return results; | ||
} | ||
|
||
/** | ||
* Extracts a list of {@link Line}s of the given content. | ||
* | ||
* @param content the content used as basis | ||
* | ||
* @return list of {@link Line}s representing the content | ||
*/ | ||
private List<Line> getLines(String content) { | ||
if (StringUtils.isEmpty(content)) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
List<Line> result = new LinkedList<>(); | ||
int lineNumber = 0; | ||
int startIndex = 0; | ||
do { | ||
int nextIndex = content.indexOf("\n", startIndex) + 1; | ||
|
||
// in case there are no further line breaks | ||
if (nextIndex == 0) { | ||
nextIndex = content.length(); | ||
} | ||
|
||
Line line = new Line(lineNumber++, startIndex, nextIndex); | ||
result.add(line); | ||
|
||
startIndex = nextIndex; | ||
} while (startIndex < content.length()); | ||
|
||
return result; | ||
} | ||
|
||
/** | ||
* Class for representing a line in a string. | ||
*/ | ||
@Value | ||
private class Line { | ||
|
||
/** | ||
* The line number. | ||
*/ | ||
int lineNumber; | ||
|
||
/** | ||
* The absolute index where the line is starting. | ||
*/ | ||
int startIndex; | ||
|
||
/** | ||
* The absolute end index where the line is ending. | ||
*/ | ||
int endIndex; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
...-ocelot-configurationserver/src/main/java/rocks/inspectit/ocelot/search/SearchResult.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package rocks.inspectit.ocelot.search; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Data; | ||
|
||
/** | ||
* This class resembles a query matched by the FileContentSearchEngine. The file variable contains the file name the | ||
* query was found in. The start variables provide information on in which line and on which column in this line a | ||
* searched substring was found. The end variable does alike for the end of the query. | ||
*/ | ||
@AllArgsConstructor | ||
@Data | ||
public class SearchResult { | ||
|
||
/** | ||
* The name of the file the match was found in. | ||
*/ | ||
private String file; | ||
|
||
/** | ||
* The start line of the match. | ||
*/ | ||
private int startLine; | ||
|
||
/** | ||
* The start column of the match in the starting line. | ||
*/ | ||
private int startColumn; | ||
|
||
/** | ||
* The end line of the match. | ||
*/ | ||
private int endLine; | ||
|
||
/** | ||
* The end column of the match in the ending line. | ||
*/ | ||
private int endColumn; | ||
|
||
} |
Oops, something went wrong.