xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/index/IndexAnalysisSettings.java (revision e779faac6ac01c406f41e81a4354cd6ed590f968)
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, Chris Fraire <cfraire@me.com>.
22  */
23 package org.opengrok.indexer.index;
24 
25 import org.opengrok.indexer.util.WhitelistObjectInputFilter;
26 
27 import java.io.ByteArrayInputStream;
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.io.ObjectInputFilter;
31 import java.io.ObjectInputStream;
32 import java.io.ObjectOutputStream;
33 import java.io.Serializable;
34 import java.util.Collections;
35 import java.util.HashMap;
36 import java.util.Map;
37 
38 /**
39  * Represents a serializable gathering of some top-level metadata concerning the
40  * operation of {@link IndexDatabase} -- and persisted therein too -- which are
41  * re-compared upon each indexing run since changes to them might require
42  * re-indexing particular files or in certain cases all files.
43  */
44 public final class IndexAnalysisSettings implements Serializable {
45 
46     private static final long serialVersionUID = 1172403004716059609L;
47 
48     private static final ObjectInputFilter serialFilter = new WhitelistObjectInputFilter(IndexAnalysisSettings.class);
49 
50     private String projectName;
51 
52     /**
53      * Nullable to allow easing this object into existing OpenGrok indexes
54      * without forcing a re-indexing.
55      * @serial
56      */
57     private Integer tabSize;
58 
59     /**
60      * Nullable to allow easing this object into existing OpenGrok indexes
61      * without forcing a re-indexing.
62      * @serial
63      */
64     private Long analyzerGuruVersion;
65 
66     /**
67      * Nullable because otherwise custom de-serialization does not work, as a
68      * {@code final} initialized value may not actually happen because Java
69      * de-serialization circumvents normal construction.
70      * @serial
71      */
72     private Map<String, Long> analyzersVersions = new HashMap<>();
73 
74     /**
75      * Gets the project name to be used to distinguish different instances of
76      * {@link IndexAnalysisSettings} that might be returned by a Lucene
77      * {@code MultiReader} search across projects.
78      * @return projectName
79      */
getProjectName()80     public String getProjectName() {
81         return projectName;
82     }
83 
84     /**
85      * Sets the project name to be used to distinguish different instances of
86      * {@link IndexAnalysisSettings} that might be returned by a Lucene
87      * {@code MultiReader} search across projects.
88      * @param value project name
89      */
setProjectName(String value)90     public void setProjectName(String value) {
91         this.projectName = value;
92     }
93 
getTabSize()94     public Integer getTabSize() {
95         return tabSize;
96     }
97 
setTabSize(Integer value)98     public void setTabSize(Integer value) {
99         this.tabSize = value;
100     }
101 
getAnalyzerGuruVersion()102     public Long getAnalyzerGuruVersion() {
103         return analyzerGuruVersion;
104     }
105 
setAnalyzerGuruVersion(Long value)106     public void setAnalyzerGuruVersion(Long value) {
107         this.analyzerGuruVersion = value;
108     }
109 
110     /**
111      * Gets the version number for the specified file type name if it exists.
112      * @param fileTypeName name of the file type
113      * @return a defined value or {@code null} if unknown
114      */
getAnalyzerVersion(String fileTypeName)115     public Long getAnalyzerVersion(String fileTypeName) {
116         return analyzersVersions.get(fileTypeName);
117     }
118 
119     /**
120      * Gets an unmodifiable view of the map of file type names to version
121      * numbers.
122      * @return a defined instance
123      */
getAnalyzersVersions()124     public Map<String, Long> getAnalyzersVersions() {
125         return Collections.unmodifiableMap(analyzersVersions);
126     }
127 
128     /**
129      * Replaces the contents of the instance's map with the {@code values}.
130      * @param values a defined instance
131      */
setAnalyzersVersions(Map<String, Long> values)132     public void setAnalyzersVersions(Map<String, Long> values) {
133         analyzersVersions.clear();
134         analyzersVersions.putAll(values);
135     }
136 
137     /**
138      * Creates a binary representation of this object.
139      * @return a byte array representing this object
140      * @throws  IOException Any exception thrown by the underlying
141      * OutputStream.
142      */
serialize()143     public byte[] serialize() throws IOException {
144         try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); var oos = new ObjectOutputStream(bytes)) {
145             oos.writeObject(this);
146             return bytes.toByteArray();
147         }
148     }
149 
150     /**
151      * De-serializes a binary representation of an {@link IndexAnalysisSettings}
152      * object.
153      * @param bytes a byte array containing the serialization
154      * @return a defined instance
155      * @throws IOException Any of the usual Input/Output related exceptions.
156      * @throws ClassNotFoundException Class of a serialized object cannot be
157      * found.
158      * @throws ClassCastException if the array contains an object of another
159      * type than {@code IndexAnalysisSettings}
160      */
deserialize(byte[] bytes)161     public static IndexAnalysisSettings deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
162         try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
163             in.setObjectInputFilter(serialFilter);
164             return (IndexAnalysisSettings) in.readObject();
165         }
166     }
167 
readObject(ObjectInputStream in)168     private void readObject(ObjectInputStream in) throws ClassNotFoundException,
169             IOException {
170 
171         boolean hasValue = in.readBoolean();
172         String vstring = in.readUTF();
173         projectName = hasValue ? vstring : null;
174 
175         hasValue = in.readBoolean();
176         int vint = in.readInt();
177         tabSize = hasValue ? vint : null;
178 
179         hasValue = in.readBoolean();
180         long vlong = in.readLong();
181         analyzerGuruVersion = hasValue ? vlong : null;
182 
183         /**
184          * De-serialization circumvents normal construction, so the following
185          * field could be null.
186          */
187         if (analyzersVersions == null) {
188             analyzersVersions = new HashMap<>();
189         }
190         int analyzerCount = in.readInt();
191         for (int i = 0; i < analyzerCount; ++i) {
192             vstring = in.readUTF();
193             vlong = in.readLong();
194             analyzersVersions.put(vstring, vlong);
195         }
196     }
197 
writeObject(ObjectOutputStream out)198     private void writeObject(ObjectOutputStream out) throws IOException {
199         out.writeBoolean(projectName != null); // hasValue
200         out.writeUTF(projectName == null ? "" : projectName);
201 
202         out.writeBoolean(tabSize != null); // hasValue
203         out.writeInt(tabSize == null ? 0 : tabSize);
204 
205         out.writeBoolean(analyzerGuruVersion != null); // hasValue
206         out.writeLong(analyzerGuruVersion == null ? 0 : analyzerGuruVersion);
207 
208         int analyzerCount = analyzersVersions.size();
209         out.writeInt(analyzerCount);
210         for (Map.Entry<String, Long> entry : analyzersVersions.entrySet()) {
211             out.writeUTF(entry.getKey());
212             out.writeLong(entry.getValue());
213             --analyzerCount;
214         }
215         if (analyzerCount != 0) {
216             throw new IllegalStateException("analyzersVersions were modified");
217         }
218     }
219 }
220