1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.search.backend.indexer.internal;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.stream.StreamSupport;
29
30 import org.apache.lucene.search.BooleanClause;
31 import org.apache.lucene.search.BooleanQuery;
32 import org.apache.lucene.search.Query;
33 import org.apache.maven.index.ArtifactAvailability;
34 import org.apache.maven.index.ArtifactInfo;
35 import org.apache.maven.index.GroupedSearchRequest;
36 import org.apache.maven.index.GroupedSearchResponse;
37 import org.apache.maven.index.Indexer;
38 import org.apache.maven.index.IteratorSearchRequest;
39 import org.apache.maven.index.IteratorSearchResponse;
40 import org.apache.maven.index.SearchType;
41 import org.apache.maven.index.context.IndexingContext;
42 import org.apache.maven.index.expr.SourcedSearchExpression;
43 import org.apache.maven.index.search.grouping.GAGrouping;
44 import org.apache.maven.search.api.MAVEN;
45 import org.apache.maven.search.api.Record;
46 import org.apache.maven.search.api.SearchRequest;
47 import org.apache.maven.search.api.request.Field;
48 import org.apache.maven.search.api.request.FieldQuery;
49 import org.apache.maven.search.api.request.Paging;
50 import org.apache.maven.search.api.support.SearchBackendSupport;
51 import org.apache.maven.search.backend.indexer.IndexerCoreSearchBackend;
52 import org.apache.maven.search.backend.indexer.IndexerCoreSearchResponse;
53
54 import static java.util.Objects.requireNonNull;
55
56
57
58
59 public class IndexerCoreSearchBackendImpl extends SearchBackendSupport implements IndexerCoreSearchBackend {
60 private static final Map<Field, org.apache.maven.index.Field> FIELD_TRANSLATION;
61
62 static {
63 HashMap<Field, org.apache.maven.index.Field> map = new HashMap<>();
64 map.put(MAVEN.GROUP_ID, org.apache.maven.index.MAVEN.GROUP_ID);
65 map.put(MAVEN.ARTIFACT_ID, org.apache.maven.index.MAVEN.ARTIFACT_ID);
66 map.put(MAVEN.VERSION, org.apache.maven.index.MAVEN.VERSION);
67 map.put(MAVEN.CLASSIFIER, org.apache.maven.index.MAVEN.CLASSIFIER);
68 map.put(MAVEN.PACKAGING, org.apache.maven.index.MAVEN.PACKAGING);
69 map.put(MAVEN.CLASS_NAME, org.apache.maven.index.MAVEN.CLASSNAMES);
70 map.put(MAVEN.FQ_CLASS_NAME, org.apache.maven.index.MAVEN.CLASSNAMES);
71 map.put(MAVEN.SHA1, org.apache.maven.index.MAVEN.SHA1);
72 FIELD_TRANSLATION = Collections.unmodifiableMap(map);
73 }
74
75 private final Indexer indexer;
76
77 private final IndexingContext indexingContext;
78
79
80
81
82 public IndexerCoreSearchBackendImpl(Indexer indexer, IndexingContext indexingContext) {
83 super(indexingContext.getId(), indexingContext.getRepositoryId());
84 this.indexer = requireNonNull(indexer);
85 this.indexingContext = indexingContext;
86 }
87
88 @Override
89 public IndexingContext getIndexingContext() {
90 return indexingContext;
91 }
92
93 @Override
94 public IndexerCoreSearchResponse search(SearchRequest searchRequest) throws IOException {
95 Paging paging = searchRequest.getPaging();
96 int totalHitsCount;
97 List<ArtifactInfo> artifactInfos = new ArrayList<>(paging.getPageSize());
98 List<Record> page = new ArrayList<>(paging.getPageSize());
99
100
101 HashSet<Field> searchedFields = new HashSet<>();
102 Query query = toQuery(searchedFields, searchRequest.getQuery());
103 if (searchedFields.contains(MAVEN.SHA1)
104 || (searchedFields.contains(MAVEN.GROUP_ID) && searchedFields.contains(MAVEN.ARTIFACT_ID))) {
105 if (!searchedFields.contains(MAVEN.CLASSIFIER)) {
106 query = new BooleanQuery.Builder()
107 .add(new BooleanClause(query, BooleanClause.Occur.MUST))
108 .add(
109 indexer.constructQuery(
110 org.apache.maven.index.MAVEN.CLASSIFIER,
111 new SourcedSearchExpression(org.apache.maven.index.Field.NOT_PRESENT)),
112 BooleanClause.Occur.MUST_NOT)
113 .build();
114 }
115 IteratorSearchRequest iteratorSearchRequest =
116 new IteratorSearchRequest(query, Collections.singletonList(indexingContext));
117 iteratorSearchRequest.setCount(paging.getPageSize());
118 iteratorSearchRequest.setStart(paging.getPageSize() * paging.getPageOffset());
119
120 try (IteratorSearchResponse iteratorSearchResponse = indexer.searchIterator(iteratorSearchRequest)) {
121 totalHitsCount = iteratorSearchResponse.getTotalHitsCount();
122 StreamSupport.stream(iteratorSearchResponse.iterator().spliterator(), false)
123 .sorted(ArtifactInfo.VERSION_COMPARATOR)
124 .forEach(ai -> {
125 artifactInfos.add(ai);
126 page.add(convert(ai, null));
127 });
128 }
129 return new IndexerCoreSearchResponseImpl(searchRequest, totalHitsCount, page, query, artifactInfos);
130 } else {
131 GroupedSearchRequest groupedSearchRequest =
132 new GroupedSearchRequest(query, new GAGrouping(), indexingContext);
133
134 try (GroupedSearchResponse groupedSearchResponse = indexer.searchGrouped(groupedSearchRequest)) {
135 totalHitsCount = groupedSearchResponse.getResults().size();
136 groupedSearchResponse.getResults().values().stream()
137 .skip((long) paging.getPageSize() * paging.getPageOffset())
138 .limit(paging.getPageSize())
139 .forEach(aig -> {
140 ArtifactInfo ai = aig.getArtifactInfos().iterator().next();
141 artifactInfos.add(ai);
142 page.add(convert(ai, aig.getArtifactInfos().size()));
143 });
144 }
145 return new IndexerCoreSearchResponseImpl(searchRequest, totalHitsCount, page, query, artifactInfos);
146 }
147 }
148
149 private Query toQuery(HashSet<Field> searchedFields, org.apache.maven.search.api.request.Query query) {
150 if (query instanceof org.apache.maven.search.api.request.BooleanQuery.And) {
151 org.apache.maven.search.api.request.BooleanQuery bq =
152 (org.apache.maven.search.api.request.BooleanQuery) query;
153 return new BooleanQuery.Builder()
154 .add(new BooleanClause(toQuery(searchedFields, bq.getLeft()), BooleanClause.Occur.MUST))
155 .add(new BooleanClause(toQuery(searchedFields, bq.getRight()), BooleanClause.Occur.MUST))
156 .build();
157 } else if (query instanceof FieldQuery) {
158 FieldQuery fq = (FieldQuery) query;
159 org.apache.maven.index.Field icFieldName = FIELD_TRANSLATION.get(fq.getField());
160 if (icFieldName != null) {
161 searchedFields.add(fq.getField());
162 if (fq.getValue().endsWith("*")) {
163 return indexer.constructQuery(icFieldName, fq.getValue(), SearchType.SCORED);
164 } else {
165 return indexer.constructQuery(icFieldName, fq.getValue(), SearchType.EXACT);
166 }
167 } else {
168 throw new IllegalArgumentException("Unsupported Indexer field: " + fq.getField());
169 }
170 }
171 return new BooleanQuery.Builder()
172 .add(new BooleanClause(
173 indexer.constructQuery(
174 org.apache.maven.index.MAVEN.GROUP_ID, query.getValue(), SearchType.SCORED),
175 BooleanClause.Occur.SHOULD))
176 .add(new BooleanClause(
177 indexer.constructQuery(
178 org.apache.maven.index.MAVEN.ARTIFACT_ID, query.getValue(), SearchType.SCORED),
179 BooleanClause.Occur.SHOULD))
180 .add(new BooleanClause(
181 indexer.constructQuery(org.apache.maven.index.MAVEN.NAME, query.getValue(), SearchType.SCORED),
182 BooleanClause.Occur.SHOULD))
183 .build();
184 }
185
186 private Record convert(ArtifactInfo ai, Integer versionCount) {
187 HashMap<Field, Object> result = new HashMap<>();
188
189 mayPut(result, MAVEN.GROUP_ID, ai.getGroupId());
190 mayPut(result, MAVEN.ARTIFACT_ID, ai.getArtifactId());
191 mayPut(result, MAVEN.VERSION, ai.getVersion());
192 mayPut(result, MAVEN.PACKAGING, ai.getPackaging());
193 mayPut(result, MAVEN.CLASSIFIER, ai.getClassifier());
194 mayPut(result, MAVEN.FILE_EXTENSION, ai.getFileExtension());
195
196 mayPut(result, MAVEN.VERSION_COUNT, versionCount);
197
198 mayPut(result, MAVEN.HAS_SOURCE, ai.getSourcesExists() == ArtifactAvailability.PRESENT);
199 mayPut(result, MAVEN.HAS_JAVADOC, ai.getJavadocExists() == ArtifactAvailability.PRESENT);
200 mayPut(result, MAVEN.HAS_GPG_SIGNATURE, ai.getSignatureExists() == ArtifactAvailability.PRESENT);
201
202 return new Record(getBackendId(), getRepositoryId(), ai.getUinfo(), ai.getLastModified(), result);
203 }
204
205 private static void mayPut(Map<Field, Object> result, Field fieldName, Object value) {
206 if (value != null) {
207 result.put(fieldName, value);
208 }
209 }
210 }