17d004396SChris Fraire /* 27d004396SChris Fraire * CDDL HEADER START 37d004396SChris Fraire * 47d004396SChris Fraire * The contents of this file are subject to the terms of the 57d004396SChris Fraire * Common Development and Distribution License (the "License"). 67d004396SChris Fraire * You may not use this file except in compliance with the License. 77d004396SChris Fraire * 87d004396SChris Fraire * See LICENSE.txt included in this distribution for the specific 97d004396SChris Fraire * language governing permissions and limitations under the License. 107d004396SChris Fraire * 117d004396SChris Fraire * When distributing Covered Code, include this CDDL HEADER in each 127d004396SChris Fraire * file and include the License file at LICENSE.txt. 137d004396SChris Fraire * If applicable, add the following below this CDDL HEADER, with the 147d004396SChris Fraire * fields enclosed by brackets "[]" replaced with your own identifying 157d004396SChris Fraire * information: Portions Copyright [yyyy] [name of copyright owner] 167d004396SChris Fraire * 177d004396SChris Fraire * CDDL HEADER END 187d004396SChris Fraire */ 197d004396SChris Fraire 207d004396SChris Fraire /* 215d9f3aa0SAdam Hornáček * Copyright (c) 2018, 2019, Chris Fraire <cfraire@me.com>. 227d004396SChris Fraire */ 237d004396SChris Fraire package org.opengrok.indexer.index; 247d004396SChris Fraire 25*e779faacSAdam Hornacek import org.opengrok.indexer.util.WhitelistObjectInputFilter; 26*e779faacSAdam Hornacek 277d004396SChris Fraire import java.io.ByteArrayInputStream; 287d004396SChris Fraire import java.io.ByteArrayOutputStream; 297d004396SChris Fraire import java.io.IOException; 30*e779faacSAdam Hornacek import java.io.ObjectInputFilter; 317d004396SChris Fraire import java.io.ObjectInputStream; 327d004396SChris Fraire import java.io.ObjectOutputStream; 337d004396SChris Fraire import java.io.Serializable; 347d004396SChris Fraire import java.util.Collections; 357d004396SChris Fraire import java.util.HashMap; 367d004396SChris Fraire import java.util.Map; 377d004396SChris Fraire 387d004396SChris Fraire /** 397d004396SChris Fraire * Represents a serializable gathering of some top-level metadata concerning the 407d004396SChris Fraire * operation of {@link IndexDatabase} -- and persisted therein too -- which are 417d004396SChris Fraire * re-compared upon each indexing run since changes to them might require 427d004396SChris Fraire * re-indexing particular files or in certain cases all files. 437d004396SChris Fraire */ 447d004396SChris Fraire public final class IndexAnalysisSettings3 implements Serializable { 457d004396SChris Fraire 467d004396SChris Fraire private static final long serialVersionUID = -4700122690707062276L; 477d004396SChris Fraire 48*e779faacSAdam Hornacek private static final ObjectInputFilter serialFilter = new WhitelistObjectInputFilter(IndexAnalysisSettings3.class); 49*e779faacSAdam Hornacek 507d004396SChris Fraire private String projectName; 517d004396SChris Fraire 527d004396SChris Fraire /** 537d004396SChris Fraire * Nullable to allow easing this object into existing OpenGrok indexes 547d004396SChris Fraire * without forcing a re-indexing. 557d004396SChris Fraire * @serial 567d004396SChris Fraire */ 577d004396SChris Fraire private Integer tabSize; 587d004396SChris Fraire 597d004396SChris Fraire /** 607d004396SChris Fraire * Nullable to allow easing this object into existing OpenGrok indexes 617d004396SChris Fraire * without forcing a re-indexing. 627d004396SChris Fraire * @serial 637d004396SChris Fraire */ 647d004396SChris Fraire private Long analyzerGuruVersion; 657d004396SChris Fraire 667d004396SChris Fraire /** 677d004396SChris Fraire * Nullable because otherwise custom de-serialization does not work, as a 687d004396SChris Fraire * {@code final} initialized value may not actually happen because Java 697d004396SChris Fraire * de-serialization circumvents normal construction. 707d004396SChris Fraire * @serial 717d004396SChris Fraire */ 727d004396SChris Fraire private Map<String, Long> analyzersVersions = new HashMap<>(); 737d004396SChris Fraire 747d004396SChris Fraire /** 757d004396SChris Fraire * Nullable because otherwise custom de-serialization does not work, as a 767d004396SChris Fraire * {@code final} initialized value may not actually happen because Java 777d004396SChris Fraire * de-serialization circumvents normal construction. We don't bother with 787d004396SChris Fraire * anything but a simple {@link HashMap} here. 797d004396SChris Fraire * @serial 807d004396SChris Fraire */ 817d004396SChris Fraire private Map<String, IndexedSymlink> indexedSymlinks = new HashMap<>(); 827d004396SChris Fraire 837d004396SChris Fraire /** 847d004396SChris Fraire * Gets the project name to be used to distinguish different instances of 857d004396SChris Fraire * {@link IndexAnalysisSettings3} that might be returned by a Lucene 867d004396SChris Fraire * {@code MultiReader} search across projects. 877d004396SChris Fraire * @return projectName 887d004396SChris Fraire */ getProjectName()897d004396SChris Fraire public String getProjectName() { 907d004396SChris Fraire return projectName; 917d004396SChris Fraire } 927d004396SChris Fraire 937d004396SChris Fraire /** 947d004396SChris Fraire * Sets the project name to be used to distinguish different instances of 957d004396SChris Fraire * {@link IndexAnalysisSettings3} that might be returned by a Lucene 967d004396SChris Fraire * {@code MultiReader} search across projects. 977d004396SChris Fraire * @param value project name 987d004396SChris Fraire */ setProjectName(String value)997d004396SChris Fraire public void setProjectName(String value) { 1007d004396SChris Fraire this.projectName = value; 1017d004396SChris Fraire } 1027d004396SChris Fraire getTabSize()1037d004396SChris Fraire public Integer getTabSize() { 1047d004396SChris Fraire return tabSize; 1057d004396SChris Fraire } 1067d004396SChris Fraire setTabSize(Integer value)1077d004396SChris Fraire public void setTabSize(Integer value) { 1087d004396SChris Fraire this.tabSize = value; 1097d004396SChris Fraire } 1107d004396SChris Fraire getAnalyzerGuruVersion()1117d004396SChris Fraire public Long getAnalyzerGuruVersion() { 1127d004396SChris Fraire return analyzerGuruVersion; 1137d004396SChris Fraire } 1147d004396SChris Fraire setAnalyzerGuruVersion(Long value)1157d004396SChris Fraire public void setAnalyzerGuruVersion(Long value) { 1167d004396SChris Fraire this.analyzerGuruVersion = value; 1177d004396SChris Fraire } 1187d004396SChris Fraire 1197d004396SChris Fraire /** 1207d004396SChris Fraire * Gets the version number for the specified file type name if it exists. 1217d004396SChris Fraire * @param fileTypeName name of the file type 1227d004396SChris Fraire * @return a defined value or {@code null} if unknown 1237d004396SChris Fraire */ getAnalyzerVersion(String fileTypeName)1247d004396SChris Fraire public Long getAnalyzerVersion(String fileTypeName) { 1257d004396SChris Fraire return analyzersVersions.get(fileTypeName); 1267d004396SChris Fraire } 1277d004396SChris Fraire 1287d004396SChris Fraire /** 1297d004396SChris Fraire * Gets an unmodifiable view of the map of file type names to version 1307d004396SChris Fraire * numbers. 1317d004396SChris Fraire * @return a defined instance 1327d004396SChris Fraire */ getAnalyzersVersions()1337d004396SChris Fraire public Map<String, Long> getAnalyzersVersions() { 1347d004396SChris Fraire return Collections.unmodifiableMap(analyzersVersions); 1357d004396SChris Fraire } 1367d004396SChris Fraire 1377d004396SChris Fraire /** 1387d004396SChris Fraire * Replaces the contents of the instance's map with the {@code values}. 1397d004396SChris Fraire * @param values a defined instance 1407d004396SChris Fraire */ setAnalyzersVersions(Map<String, Long> values)1417d004396SChris Fraire public void setAnalyzersVersions(Map<String, Long> values) { 1427d004396SChris Fraire analyzersVersions.clear(); 1437d004396SChris Fraire analyzersVersions.putAll(values); 1447d004396SChris Fraire } 1457d004396SChris Fraire 1467d004396SChris Fraire /** 1477d004396SChris Fraire * Gets an unmodifiable view of the map of canonical file names to symlinks. 1487d004396SChris Fraire * @return a defined instance 1497d004396SChris Fraire */ getIndexedSymlinks()1507d004396SChris Fraire public Map<String, IndexedSymlink> getIndexedSymlinks() { 1517d004396SChris Fraire return Collections.unmodifiableMap(indexedSymlinks); 1527d004396SChris Fraire } 1537d004396SChris Fraire 1547d004396SChris Fraire /** 1557d004396SChris Fraire * Replaces the contents of the instance's map with the {@code values}. 1567d004396SChris Fraire * @param values a defined instance 1577d004396SChris Fraire */ setIndexedSymlinks(Map<String, IndexedSymlink> values)1587d004396SChris Fraire public void setIndexedSymlinks(Map<String, IndexedSymlink> values) { 1597d004396SChris Fraire indexedSymlinks.clear(); 1607d004396SChris Fraire indexedSymlinks.putAll(values); 1617d004396SChris Fraire } 1627d004396SChris Fraire 1637d004396SChris Fraire /** 1647d004396SChris Fraire * Creates a binary representation of this object. 1657d004396SChris Fraire * @return a byte array representing this object 1667d004396SChris Fraire * @throws IOException Any exception thrown by the underlying 1677d004396SChris Fraire * OutputStream. 1687d004396SChris Fraire */ serialize()1697d004396SChris Fraire public byte[] serialize() throws IOException { 170*e779faacSAdam Hornacek try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); var oos = new ObjectOutputStream(bytes)) { 171*e779faacSAdam Hornacek oos.writeObject(this); 1727d004396SChris Fraire return bytes.toByteArray(); 1737d004396SChris Fraire } 174*e779faacSAdam Hornacek } 1757d004396SChris Fraire 1767d004396SChris Fraire /** 1777d004396SChris Fraire * De-serializes a binary representation of an {@link IndexAnalysisSettings3} 1787d004396SChris Fraire * object. 1797d004396SChris Fraire * @param bytes a byte array containing the serialization 1807d004396SChris Fraire * @return a defined instance 1817d004396SChris Fraire * @throws IOException Any of the usual Input/Output related exceptions. 1827d004396SChris Fraire * @throws ClassNotFoundException Class of a serialized object cannot be 1837d004396SChris Fraire * found. 1847d004396SChris Fraire * @throws ClassCastException if the array contains an object of another 1857d004396SChris Fraire * type than {@code IndexAnalysisSettings} 1867d004396SChris Fraire */ deserialize(byte[] bytes)187*e779faacSAdam Hornacek public static IndexAnalysisSettings3 deserialize(byte[] bytes) throws IOException, ClassNotFoundException { 188*e779faacSAdam Hornacek try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) { 189*e779faacSAdam Hornacek in.setObjectInputFilter(serialFilter); 1907d004396SChris Fraire return (IndexAnalysisSettings3) in.readObject(); 1917d004396SChris Fraire } 192*e779faacSAdam Hornacek } 1937d004396SChris Fraire 1947d004396SChris Fraire @SuppressWarnings("Duplicates") readObject(ObjectInputStream in)1957d004396SChris Fraire private void readObject(ObjectInputStream in) throws ClassNotFoundException, 1967d004396SChris Fraire IOException { 1977d004396SChris Fraire 1987d004396SChris Fraire boolean hasValue = in.readBoolean(); 1997d004396SChris Fraire String vString = in.readUTF(); 2007d004396SChris Fraire projectName = hasValue ? vString : null; 2017d004396SChris Fraire 2027d004396SChris Fraire hasValue = in.readBoolean(); 2037d004396SChris Fraire int vInteger = in.readInt(); 2047d004396SChris Fraire tabSize = hasValue ? vInteger : null; 2057d004396SChris Fraire 2067d004396SChris Fraire hasValue = in.readBoolean(); 2077d004396SChris Fraire long vLong = in.readLong(); 2087d004396SChris Fraire analyzerGuruVersion = hasValue ? vLong : null; 2097d004396SChris Fraire 2107d004396SChris Fraire /* 2117d004396SChris Fraire * De-serialization circumvents normal construction, so the following 2127d004396SChris Fraire * field could be null. 2137d004396SChris Fraire */ 2147d004396SChris Fraire if (analyzersVersions == null) { 2157d004396SChris Fraire analyzersVersions = new HashMap<>(); 2167d004396SChris Fraire } 2177d004396SChris Fraire int analyzerCount = in.readInt(); 2187d004396SChris Fraire for (int i = 0; i < analyzerCount; ++i) { 2197d004396SChris Fraire vString = in.readUTF(); 2207d004396SChris Fraire vLong = in.readLong(); 2217d004396SChris Fraire analyzersVersions.put(vString, vLong); 2227d004396SChris Fraire } 2237d004396SChris Fraire 2247d004396SChris Fraire /* 2257d004396SChris Fraire * De-serialization circumvents normal construction, so the following 2267d004396SChris Fraire * field could be null. 2277d004396SChris Fraire */ 2287d004396SChris Fraire if (indexedSymlinks == null) { 2297d004396SChris Fraire indexedSymlinks = new HashMap<>(); 2307d004396SChris Fraire } 2317d004396SChris Fraire int symlinkCount = in.readInt(); 2327d004396SChris Fraire for (int i = 0; i < symlinkCount; ++i) { 2337d004396SChris Fraire String absolute = in.readUTF(); 2347d004396SChris Fraire String canonical = in.readUTF(); 2357d004396SChris Fraire boolean isLocal = in.readBoolean(); 2367d004396SChris Fraire IndexedSymlink indexed = new IndexedSymlink(absolute, canonical, isLocal); 2377d004396SChris Fraire indexedSymlinks.put(canonical, indexed); 2387d004396SChris Fraire } 2397d004396SChris Fraire } 2407d004396SChris Fraire 2417d004396SChris Fraire @SuppressWarnings("Duplicates") writeObject(ObjectOutputStream out)2427d004396SChris Fraire private void writeObject(ObjectOutputStream out) throws IOException { 2437d004396SChris Fraire out.writeBoolean(projectName != null); // hasValue 2447d004396SChris Fraire out.writeUTF(projectName == null ? "" : projectName); 2457d004396SChris Fraire 2467d004396SChris Fraire out.writeBoolean(tabSize != null); // hasValue 2477d004396SChris Fraire out.writeInt(tabSize == null ? 0 : tabSize); 2487d004396SChris Fraire 2497d004396SChris Fraire out.writeBoolean(analyzerGuruVersion != null); // hasValue 2507d004396SChris Fraire out.writeLong(analyzerGuruVersion == null ? 0 : analyzerGuruVersion); 2517d004396SChris Fraire 2527d004396SChris Fraire int collectionCount = analyzersVersions.size(); 2537d004396SChris Fraire out.writeInt(collectionCount); 2547d004396SChris Fraire for (Map.Entry<String, Long> entry : analyzersVersions.entrySet()) { 2557d004396SChris Fraire out.writeUTF(entry.getKey()); 2567d004396SChris Fraire out.writeLong(entry.getValue()); 2577d004396SChris Fraire --collectionCount; 2587d004396SChris Fraire } 2597d004396SChris Fraire if (collectionCount != 0) { 2607d004396SChris Fraire throw new IllegalStateException("analyzersVersions were modified"); 2617d004396SChris Fraire } 2627d004396SChris Fraire 2637d004396SChris Fraire collectionCount = indexedSymlinks.size(); 2647d004396SChris Fraire out.writeInt(collectionCount); 2657d004396SChris Fraire for (IndexedSymlink entry : indexedSymlinks.values()) { 2667d004396SChris Fraire out.writeUTF(entry.getAbsolute()); 2677d004396SChris Fraire out.writeUTF(entry.getCanonical()); 2687d004396SChris Fraire out.writeBoolean(entry.isLocal()); 2697d004396SChris Fraire --collectionCount; 2707d004396SChris Fraire } 2717d004396SChris Fraire if (collectionCount != 0) { 2727d004396SChris Fraire throw new IllegalStateException("indexedSymlinks were modified"); 2737d004396SChris Fraire } 2747d004396SChris Fraire } 2757d004396SChris Fraire } 276