package com.cadrlife.devsearch.agent.service.analysis; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import org.elasticsearch.action.search.*; import org.elasticsearch.client.Client; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Named; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; public class JavaReferenceFinder { private static final Logger LOG = LoggerFactory.getLogger(JavaReferenceFinder.class); static final String DOC_INDEX = "doc"; private Client esClient; private String codeIndex; TimeValue keepAlive = new TimeValue(5, TimeUnit.MINUTES); Cache<String, Set<String>> classNamesByPackageCache = CacheBuilder.newBuilder().maximumSize(30).build(); @Inject public JavaReferenceFinder(Client esClient, @Named("elasticsearch.code.index") String codeIndex) { this.esClient = esClient; this.codeIndex = codeIndex; } public void populateReferences(JavaAnalysis analysis, String content) { extractImportsToReferences((Iterable) analysis.getImports(), analysis.getReferences()); addSamePackageReferences(analysis.getJavaPackage(), analysis.getName(), content, analysis.getReferences()); } void addSamePackageReferences(final String javaPackage, String javaName, final String contents, final List<String> references) { // System.out.println("finding all classes with package '" + javaPackage + "'"); try { Set<String> classNames = classNamesByPackageCache.get(javaPackage, new Callable<Set<String>>() { @Override public Set<String> call() throws Exception { // System.out.println("Cache miss"); Set<String> classNames = new HashSet<>(); SearchResponse response = esClient.prepareSearch(codeIndex).addField("javaName").setSearchType(SearchType.SCAN).setTypes(DOC_INDEX) .setQuery(QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("javaPackage", javaPackage)) ).setSize(50).setScroll(keepAlive).execute().actionGet(); while (true) { response = esClient.prepareSearchScroll(response.getScrollId()).setScroll(keepAlive).execute().actionGet(); for (SearchHit hit : response.getHits()) { String javaName = hit.field("javaName").getValue(); classNames.add(javaName); // System.out.println(" " + javaName); // references.add(IdUtil.docRef(javaPackage + "." + javaName, hit.getId())); } if (response.getHits().getHits().length == 0) { break; } } return classNames; } }); for (String className : classNames) { if (!javaName.equals(className) && contents.matches("(?s).*\\b" + className + "\\b.*")) { // System.out.println("*** MATCH " + className + " used by " + javaName); references.add(javaRef(javaPackage, className)); } } } catch (ExecutionException e) { throw new RuntimeException(e); } } private String javaRef(String javaPackage, String className) { return javaPackage + "." + className; } void extractImportsToReferences(Iterable javaImports, List<String> references) { MultiSearchRequestBuilder multiSearchRequest = esClient.prepareMultiSearch(); List<String> potentialJavaRefs = new ArrayList<>(); for (Object javaImport : javaImports) { String[] pieces = javaImport.toString().split("\\."); String javaName = pieces[pieces.length-1]; try { String javaPackage = javaImport.toString().substring(0, javaImport.toString().length() - javaName.length() - 1); // System.out.println("Name " + javaName + " pak " + javaPackage); potentialJavaRefs.add(javaRef(javaPackage, javaName)); multiSearchRequest.add(createJavaRefSearch(javaPackage, javaName)); } catch (StringIndexOutOfBoundsException e) { System.out.println("Failed to analyze java import " + javaImport); } } if (!potentialJavaRefs.isEmpty()) { MultiSearchResponse.Item[] responseItems = multiSearchRequest.execute().actionGet().getResponses(); for (int i = 0; i < responseItems.length; i++) { String potentialJavaRef = potentialJavaRefs.get(i); if (responseItems[i].isFailure()) { LOG.error("Search for java ref {}: {}", potentialJavaRef, responseItems[i].getFailureMessage()); } else if (responseItems[i].getResponse().getHits().getTotalHits() > 0) { references.add(potentialJavaRef); } } } } private SearchRequestBuilder createJavaRefSearch(String javaPackage, String javaName) { // String javaRef = javaRef(javaPackage, javaName); return esClient.prepareSearch(codeIndex).setTypes(DOC_INDEX) .setQuery(QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("javaPackage", javaPackage)) .must(QueryBuilders.termQuery("javaName", javaName)) ).setNoFields().setSize(0); // return searchRequestBuilder; } // MultiSearchResponse multiSearchResponse = esClient.prepareMultiSearch().add(search).execute().actionGet(); // // SearchResponse response = .execute().actionGet(); // for (SearchHit hit : response.getHits()) { // // references.add(java); // } // } }