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