View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.index.context;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.nio.file.Files;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Date;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Set;
30  
31  import org.apache.lucene.analysis.Analyzer;
32  import org.apache.lucene.index.IndexWriter;
33  import org.apache.lucene.search.IndexSearcher;
34  import org.apache.lucene.store.Directory;
35  import org.apache.lucene.store.FSDirectory;
36  import org.apache.maven.index.artifact.GavCalculator;
37  import org.apache.maven.index.artifact.M2GavCalculator;
38  
39  /**
40   * A merged indexing context that offers read only "view" on multiple other indexing contexts merged and presented as
41   * one. Usable for searching and publishing, but all write operations are basically noop.
42   *
43   * @author cstamas
44   */
45  public class MergedIndexingContext extends AbstractIndexingContext {
46      private final String id;
47  
48      private final String repositoryId;
49  
50      private final File repository;
51  
52      private final ContextMemberProvider membersProvider;
53  
54      private final GavCalculator gavCalculator;
55  
56      private final Directory directory;
57  
58      private File directoryFile;
59  
60      private boolean searchable;
61  
62      private MergedIndexingContext(
63              ContextMemberProvider membersProvider,
64              String id,
65              String repositoryId,
66              File repository,
67              Directory indexDirectory,
68              boolean searchable)
69              throws IOException {
70          this.id = id;
71          this.repositoryId = repositoryId;
72          this.repository = repository;
73          this.membersProvider = membersProvider;
74          this.gavCalculator = new M2GavCalculator();
75          this.directory = indexDirectory;
76          this.searchable = searchable;
77          setIndexDirectoryFile(null);
78      }
79  
80      public MergedIndexingContext(
81              String id,
82              String repositoryId,
83              File repository,
84              File indexDirectoryFile,
85              boolean searchable,
86              ContextMemberProvider membersProvider)
87              throws IOException {
88          this(membersProvider, id, repositoryId, repository, FSDirectory.open(indexDirectoryFile.toPath()), searchable);
89  
90          setIndexDirectoryFile(indexDirectoryFile);
91      }
92  
93      @Deprecated
94      public MergedIndexingContext(
95              String id,
96              String repositoryId,
97              File repository,
98              Directory indexDirectory,
99              boolean searchable,
100             ContextMemberProvider membersProvider)
101             throws IOException {
102         this(membersProvider, id, repositoryId, repository, indexDirectory, searchable);
103 
104         if (indexDirectory instanceof FSDirectory) {
105             setIndexDirectoryFile(((FSDirectory) indexDirectory).getDirectory().toFile());
106         }
107     }
108 
109     public Collection<IndexingContext> getMembers() {
110         return membersProvider.getMembers();
111     }
112 
113     public String getId() {
114         return id;
115     }
116 
117     public String getRepositoryId() {
118         return repositoryId;
119     }
120 
121     public File getRepository() {
122         return repository;
123     }
124 
125     public String getRepositoryUrl() {
126         return null;
127     }
128 
129     public String getIndexUpdateUrl() {
130         return null;
131     }
132 
133     public boolean isSearchable() {
134         return searchable;
135     }
136 
137     public void setSearchable(boolean searchable) {
138         this.searchable = searchable;
139     }
140 
141     public Date getTimestamp() {
142         Date ts = null;
143 
144         for (IndexingContext ctx : getMembers()) {
145             Date cts = ctx.getTimestamp();
146 
147             if (cts != null) {
148                 if (ts == null || cts.after(ts)) {
149                     ts = cts;
150                 }
151             }
152         }
153 
154         return ts;
155     }
156 
157     public void updateTimestamp() throws IOException {
158         // noop
159     }
160 
161     public void updateTimestamp(boolean save) throws IOException {
162         // noop
163     }
164 
165     public void updateTimestamp(boolean save, Date date) throws IOException {
166         // noop
167     }
168 
169     public int getSize() throws IOException {
170         int size = 0;
171 
172         for (IndexingContext ctx : getMembers()) {
173             size += ctx.getSize();
174         }
175 
176         return size;
177     }
178 
179     public IndexSearcher acquireIndexSearcher() throws IOException {
180         final NexusIndexMultiReader mr = new NexusIndexMultiReader(getMembers());
181         return new NexusIndexMultiSearcher(mr);
182     }
183 
184     public void releaseIndexSearcher(IndexSearcher indexSearcher) throws IOException {
185         if (indexSearcher instanceof NexusIndexMultiSearcher) {
186             ((NexusIndexMultiSearcher) indexSearcher).release();
187         } else {
188             throw new IllegalArgumentException(String.format(
189                     "Illegal argument to merged idexing context: it emits class %s but and cannot release class %s!",
190                     NexusIndexMultiSearcher.class.getName(),
191                     indexSearcher.getClass().getName()));
192         }
193     }
194 
195     public IndexWriter getIndexWriter() throws IOException {
196         throw new UnsupportedOperationException(getClass().getName() + " indexing context is read-only!");
197     }
198 
199     public List<IndexCreator> getIndexCreators() {
200         HashSet<IndexCreator> creators = new HashSet<>();
201 
202         for (IndexingContext ctx : getMembers()) {
203             creators.addAll(ctx.getIndexCreators());
204         }
205 
206         return new ArrayList<>(creators);
207     }
208 
209     public Analyzer getAnalyzer() {
210         return new NexusAnalyzer();
211     }
212 
213     public void commit() throws IOException {
214         // noop
215     }
216 
217     public void rollback() throws IOException {
218         // noop
219     }
220 
221     public void optimize() throws IOException {
222         // noop
223     }
224 
225     public void close(boolean deleteFiles) throws IOException {
226         // noop
227     }
228 
229     public void purge() throws IOException {
230         // noop
231     }
232 
233     public void merge(Directory directory) throws IOException {
234         // noop
235     }
236 
237     public void merge(Directory directory, DocumentFilter filter) throws IOException {
238         // noop
239     }
240 
241     public void merge(Directory directory, DocumentFilter filter, Set<String> allGroups, Set<String> rootGroups)
242             throws IOException {
243         // noop
244     }
245 
246     public void replace(Directory directory) throws IOException {
247         // noop
248     }
249 
250     public void replace(Directory directory, Set<String> allGroups, Set<String> rootGroups) throws IOException {
251         // noop
252     }
253 
254     public Directory getIndexDirectory() {
255         return directory;
256     }
257 
258     public File getIndexDirectoryFile() {
259         return directoryFile;
260     }
261 
262     /**
263      * Sets index location. As usually index is persistent (is on disk), this will point to that value, but in
264      * some circumstances (ie, using RAMDisk for index), this will point to an existing tmp directory.
265      */
266     protected void setIndexDirectoryFile(File dir) throws IOException {
267         if (dir == null) {
268             // best effort, to have a directory through the life of a ctx
269             this.directoryFile = Files.createTempDirectory("mindexer-ctx" + id).toFile();
270             this.directoryFile.deleteOnExit();
271         } else {
272             this.directoryFile = dir;
273         }
274     }
275 
276     public GavCalculator getGavCalculator() {
277         return gavCalculator;
278     }
279 
280     public void setAllGroups(Collection<String> groups) throws IOException {
281         // noop
282     }
283 
284     public Set<String> getAllGroups() throws IOException {
285         HashSet<String> result = new HashSet<>();
286 
287         for (IndexingContext ctx : getMembers()) {
288             result.addAll(ctx.getAllGroups());
289         }
290 
291         return result;
292     }
293 
294     public void setRootGroups(Collection<String> groups) throws IOException {
295         // noop
296     }
297 
298     public Set<String> getRootGroups() throws IOException {
299         HashSet<String> result = new HashSet<>();
300 
301         for (IndexingContext ctx : getMembers()) {
302             result.addAll(ctx.getRootGroups());
303         }
304 
305         return result;
306     }
307 
308     public void rebuildGroups() throws IOException {
309         // noop
310     }
311 }