xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/index/IndexAnalysisSettingsAccessor.java (revision 5d9f3aa0ca3da3a714233f987fa732f62c0965f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2018, 2019, Chris Fraire <cfraire@me.com>.
22  */
23 package org.opengrok.indexer.index;
24 
25 import java.io.IOException;
26 import org.apache.lucene.document.Document;
27 import org.apache.lucene.document.Field;
28 import org.apache.lucene.document.StoredField;
29 import org.apache.lucene.document.StringField;
30 import org.apache.lucene.index.IndexReader;
31 import org.apache.lucene.index.IndexWriter;
32 import org.apache.lucene.index.IndexableField;
33 import org.apache.lucene.index.Term;
34 import org.apache.lucene.queryparser.classic.ParseException;
35 import org.apache.lucene.queryparser.classic.QueryParser;
36 import org.apache.lucene.search.IndexSearcher;
37 import org.apache.lucene.search.Query;
38 import org.apache.lucene.search.TopDocs;
39 import org.opengrok.indexer.analysis.CompatibleAnalyser;
40 import org.opengrok.indexer.search.QueryBuilder;
41 
42 /**
43  * Represents a data-access object for {@link IndexAnalysisSettings}.
44  */
45 public class IndexAnalysisSettingsAccessor {
46 
47     /**
48      * The {@link QueryBuilder}-normalized value for UUID 58859C75-F941-42E5-8D1A-FAF71DDEBBA7.
49      */
50     static final String INDEX_ANALYSIS_SETTINGS_OBJUID = "uthuslvotkgltggqqjmurqojpjpjjkutkujktnkk";
51 
52     private static final int INDEX_ANALYSIS_SETTINGS_OBJVER = 3;
53 
54     /**
55      * Searches for a document with a {@link QueryBuilder#OBJUID} value matching
56      * {@link #INDEX_ANALYSIS_SETTINGS_OBJUID}. The first document found is
57      * returned, so this should not be called with a MultiReader.
58      * @param reader a defined instance
59      * @return a defined instance or {@code null} if none could be found
60      * @throws IOException if I/O error occurs while searching Lucene
61      */
read(IndexReader reader)62     public IndexAnalysisSettings3 read(IndexReader reader) throws IOException {
63         IndexAnalysisSettings3[] res = read(reader, 1);
64         return res.length > 0 ? res[0] : null;
65     }
66 
67     /**
68      * Searches for documents with a {@link QueryBuilder#OBJUID} value matching
69      * {@link #INDEX_ANALYSIS_SETTINGS_OBJUID}.
70      * @param reader a defined instance
71      * @param n a limit to the number of documents returned. The method may
72      * return less.
73      * @return a defined instance, which is empty if none could be found
74      * @throws IOException if I/O error occurs while searching Lucene
75      */
read(IndexReader reader, int n)76     public IndexAnalysisSettings3[] read(IndexReader reader, int n)
77             throws IOException {
78         IndexSearcher searcher = new IndexSearcher(reader);
79         Query q;
80         try {
81             q = new QueryParser(QueryBuilder.OBJUID, new CompatibleAnalyser()).
82                 parse(INDEX_ANALYSIS_SETTINGS_OBJUID);
83         } catch (ParseException ex) {
84             // This is not expected, so translate to RuntimeException.
85             throw new RuntimeException(ex);
86         }
87         TopDocs top = searcher.search(q, n);
88 
89         int nres = top.totalHits.value > n ? n : (int) top.totalHits.value;
90         IndexAnalysisSettings3[] res = new IndexAnalysisSettings3[nres];
91 
92         IndexAnalysisSettingsUpgrader upgrader = new IndexAnalysisSettingsUpgrader();
93         for (int i = 0; i < nres; ++i) {
94             Document doc = searcher.doc(top.scoreDocs[i].doc);
95             IndexableField objser = doc.getField(QueryBuilder.OBJSER);
96             int objver = readObjectVersion(doc);
97             try {
98                 res[i] = objser == null ? null : upgrader.upgrade(
99                         objser.binaryValue().bytes, objver);
100             } catch (ClassNotFoundException ex) {
101                 // This is not expected, so translate to RuntimeException.
102                 throw new RuntimeException(ex);
103             }
104         }
105         return res;
106     }
107 
108     /**
109      * Writes a document to contain the serialized version of {@code settings},
110      * with a {@link QueryBuilder#OBJUID} value set to
111      * {@link #INDEX_ANALYSIS_SETTINGS_OBJUID}. An existing version of the
112      * document is first deleted.
113      * @param writer a defined, target instance
114      * @param settings a defined instance
115      * @throws IOException if I/O error occurs while writing Lucene
116      */
write(IndexWriter writer, IndexAnalysisSettings3 settings)117     public void write(IndexWriter writer, IndexAnalysisSettings3 settings)
118             throws IOException {
119         byte[] objser = settings.serialize();
120 
121         writer.deleteDocuments(new Term(QueryBuilder.OBJUID,
122             INDEX_ANALYSIS_SETTINGS_OBJUID));
123 
124         Document doc = new Document();
125         StringField uidfield = new StringField(QueryBuilder.OBJUID,
126             INDEX_ANALYSIS_SETTINGS_OBJUID, Field.Store.NO);
127         doc.add(uidfield);
128         doc.add(new StoredField(QueryBuilder.OBJSER, objser));
129         doc.add(new StoredField(QueryBuilder.OBJVER,
130             INDEX_ANALYSIS_SETTINGS_OBJVER));
131         writer.addDocument(doc);
132     }
133 
readObjectVersion(Document doc)134     private int readObjectVersion(Document doc) {
135         IndexableField objver = doc.getField(QueryBuilder.OBJVER);
136         return objver == null ? 1 : objver.numericValue().intValue();
137     }
138 }
139