1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.index;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.IOException;
28 import java.security.MessageDigest;
29 import java.security.NoSuchAlgorithmException;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.List;
34
35 import org.apache.lucene.queryparser.classic.ParseException;
36 import org.apache.lucene.search.Query;
37 import org.apache.maven.index.context.ContextMemberProvider;
38 import org.apache.maven.index.context.DefaultIndexingContext;
39 import org.apache.maven.index.context.ExistingLuceneIndexMismatchException;
40 import org.apache.maven.index.context.IndexCreator;
41 import org.apache.maven.index.context.IndexingContext;
42 import org.apache.maven.index.context.MergedIndexingContext;
43 import org.apache.maven.index.expr.SearchExpression;
44 import org.apache.maven.index.expr.SearchTypedStringSearchExpression;
45 import org.apache.maven.index.expr.SourcedSearchExpression;
46 import org.apache.maven.index.util.IndexCreatorSorter;
47
48
49
50
51
52
53 @Singleton
54 @Named
55 public class DefaultIndexer implements Indexer {
56
57 private final SearchEngine searcher;
58
59 private final IndexerEngine indexerEngine;
60
61 private final QueryCreator queryCreator;
62
63 @Inject
64 public DefaultIndexer(SearchEngine searcher, IndexerEngine indexerEngine, QueryCreator queryCreator) {
65 this.searcher = searcher;
66 this.indexerEngine = indexerEngine;
67 this.queryCreator = queryCreator;
68 }
69
70
71
72
73
74 public IndexingContext createIndexingContext(
75 String id,
76 String repositoryId,
77 File repository,
78 File indexDirectory,
79 String repositoryUrl,
80 String indexUpdateUrl,
81 boolean searchable,
82 boolean reclaim,
83 List<? extends IndexCreator> indexers)
84 throws IOException, ExistingLuceneIndexMismatchException, IllegalArgumentException {
85 final IndexingContext context = new DefaultIndexingContext(
86 id,
87 repositoryId,
88 repository,
89 indexDirectory,
90 repositoryUrl,
91 indexUpdateUrl,
92 IndexCreatorSorter.sort(indexers),
93 reclaim);
94 context.setSearchable(searchable);
95 return context;
96 }
97
98 public IndexingContext createMergedIndexingContext(
99 String id,
100 String repositoryId,
101 File repository,
102 File indexDirectory,
103 boolean searchable,
104 ContextMemberProvider membersProvider)
105 throws IOException {
106 IndexingContext context =
107 new MergedIndexingContext(id, repositoryId, repository, indexDirectory, searchable, membersProvider);
108 return context;
109 }
110
111 public void closeIndexingContext(IndexingContext context, boolean deleteFiles) throws IOException {
112 context.close(deleteFiles);
113 }
114
115
116
117
118
119 public void addArtifactToIndex(ArtifactContext ac, IndexingContext context) throws IOException {
120 if (ac != null) {
121 indexerEngine.update(context, ac);
122
123 context.commit();
124 }
125 }
126
127 public void addArtifactsToIndex(Collection<ArtifactContext> ac, IndexingContext context) throws IOException {
128 if (ac != null && !ac.isEmpty()) {
129 for (ArtifactContext actx : ac) {
130 indexerEngine.update(context, actx);
131 }
132
133 context.commit();
134 }
135 }
136
137 public void deleteArtifactsFromIndex(Collection<ArtifactContext> ac, IndexingContext context) throws IOException {
138 if (ac != null && !ac.isEmpty()) {
139 for (ArtifactContext actx : ac) {
140 indexerEngine.remove(context, actx);
141
142 context.commit();
143 }
144 }
145 }
146
147
148
149
150
151 public FlatSearchResponse searchFlat(FlatSearchRequest request) throws IOException {
152 if (request.getContexts().isEmpty()) {
153 return new FlatSearchResponse(request.getQuery(), 0, Collections.emptySet());
154 } else {
155 return searcher.forceSearchFlatPaged(request, request.getContexts());
156 }
157 }
158
159 public IteratorSearchResponse searchIterator(IteratorSearchRequest request) throws IOException {
160 if (request.getContexts().isEmpty()) {
161 return IteratorSearchResponse.empty(request.getQuery());
162 } else {
163 return searcher.forceSearchIteratorPaged(request, request.getContexts());
164 }
165 }
166
167 public GroupedSearchResponse searchGrouped(GroupedSearchRequest request) throws IOException {
168 if (request.getContexts().isEmpty()) {
169 return new GroupedSearchResponse(request.getQuery(), 0, Collections.emptyMap());
170 } else {
171
172 return searcher.forceSearchGrouped(request, request.getContexts());
173 }
174 }
175
176
177
178
179
180 public Collection<ArtifactInfo> identify(final File artifact, final Collection<IndexingContext> contexts)
181 throws IOException {
182 try (FileInputStream is = new FileInputStream(artifact)) {
183 final MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
184 final byte[] buff = new byte[4096];
185 int n;
186 while ((n = is.read(buff)) > -1) {
187 sha1.update(buff, 0, n);
188 }
189 byte[] digest = sha1.digest();
190 return identify(constructQuery(MAVEN.SHA1, new SourcedSearchExpression(encode(digest))), contexts);
191 } catch (NoSuchAlgorithmException ex) {
192 throw new IOException("Unable to calculate digest", ex);
193 }
194 }
195
196 public Collection<ArtifactInfo> identify(Query query, Collection<IndexingContext> contexts) throws IOException {
197 try (IteratorSearchResponse result = searcher.searchIteratorPaged(new IteratorSearchRequest(query), contexts)) {
198 final List<ArtifactInfo> ais = new ArrayList<>(result.getTotalHitsCount());
199 for (ArtifactInfo ai : result) {
200 ais.add(ai);
201 }
202 return ais;
203 }
204 }
205
206
207
208
209
210 public Query constructQuery(Field field, SearchExpression expression) throws IllegalArgumentException {
211 try {
212 return queryCreator.constructQuery(field, expression);
213 } catch (ParseException e) {
214 throw new IllegalArgumentException(e);
215 }
216 }
217
218 public Query constructQuery(Field field, String expression, SearchType searchType) throws IllegalArgumentException {
219 return constructQuery(field, new SearchTypedStringSearchExpression(expression, searchType));
220 }
221
222
223 private static final char[] DIGITS = "0123456789abcdef".toCharArray();
224
225 private static String encode(byte[] digest) {
226 char[] buff = new char[digest.length * 2];
227
228 int n = 0;
229
230 for (byte b : digest) {
231 buff[n++] = DIGITS[(0xF0 & b) >> 4];
232 buff[n++] = DIGITS[0x0F & b];
233 }
234
235 return new String(buff);
236 }
237 }