Skip to content

Commit 1981acb

Browse files
committed
Introducing an plugin framework for analyzers
- loading analyzers implementing an interface from a directory - augmenting analyzer guru to use the loaded plugins - making analyzer guru a property of RuntimeEnvironment - loading the default analyzers as it used to be approaches #2588
1 parent 670ee78 commit 1981acb

28 files changed

+1222
-933
lines changed

dev/checkstyle/suppressions.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Portions Copyright (c) 2018-2019, Chris Fraire <[email protected]>.
3737

3838
<suppress checks="ParameterNumber" files="CtagsReader\.java|Definitions\.java|
3939
|JFlexXrefUtils\.java|FileAnalyzerFactory\.java|SearchController\.java|
40-
|Context\.java|HistoryContext\.java|Suggester\.java" />
40+
|Context\.java|HistoryContext\.java|Suggester\.java|AnalyzersInfo\.java" />
4141

4242
<suppress checks="MethodLength" files="Indexer\.java" />
4343
</suppressions>

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/AnalyzerFramework.java

Lines changed: 400 additions & 0 deletions
Large diffs are not rendered by default.

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/AnalyzerGuru.java

Lines changed: 365 additions & 618 deletions
Large diffs are not rendered by default.

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/AnalyzerGuruHelp.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,40 +35,41 @@
3535
public class AnalyzerGuruHelp {
3636
/**
3737
* Gets a reportable hunk of text that details
38-
* {@link AnalyzerGuru#getPrefixesMap()},
39-
* {@link AnalyzerGuru#getExtensionsMap()},
40-
* {@link AnalyzerGuru#getMagicsMap()}, and
41-
* {@link AnalyzerGuru#getAnalyzerFactoryMatchers()}.
38+
* {@link AnalyzerFramework#getPrefixesMap()},
39+
* {@link AnalyzerFramework#getExtensionsMap()},
40+
* {@link AnalyzerFramework#getMagicsMap()}, and
41+
* {@link AnalyzerFramework#getAnalyzerFactoryMatchers()}.
4242
* @return a defined, multi-line String
43+
* @param analyzerGuru
4344
*/
44-
public static String getUsage() {
45+
public static String getUsage(AnalyzerGuru analyzerGuru) {
4546
StringBuilder b = new StringBuilder();
4647
b.append("AnalyzerGuru prefixes:\n");
47-
byKey(AnalyzerGuru.getPrefixesMap()).forEach((kv) -> {
48+
byKey(analyzerGuru.getPrefixesMap()).forEach((kv) -> {
4849
b.append(String.format("%-10s : %s\n", reportable(kv.key + '*'),
4950
reportable(kv.fac)));
5051
});
5152

5253
b.append("\nAnalyzerGuru extensions:\n");
53-
byKey(AnalyzerGuru.getExtensionsMap()).forEach((kv) -> {
54+
byKey(analyzerGuru.getExtensionsMap()).forEach((kv) -> {
5455
b.append(String.format("*.%-7s : %s\n",
5556
reportable(kv.key.toLowerCase(Locale.ROOT)),
5657
reportable(kv.fac)));
5758
});
5859

5960
b.append("\nAnalyzerGuru magic strings:\n");
60-
byFactory(AnalyzerGuru.getMagicsMap()).forEach((kv) -> {
61+
byFactory(analyzerGuru.getMagicsMap()).forEach((kv) -> {
6162
b.append(String.format("%-23s : %s\n", reportable(kv.key),
6263
reportable(kv.fac)));
6364
});
6465

6566
b.append("\nAnalyzerGuru magic matchers:\n");
66-
AnalyzerGuru.getAnalyzerFactoryMatchers().forEach((m) -> {
67+
analyzerGuru.getAnalyzerFactoryMatchers().forEach((m) -> {
6768
if (m.getIsPreciseMagic()) {
6869
b.append(reportable(m));
6970
}
7071
});
71-
AnalyzerGuru.getAnalyzerFactoryMatchers().forEach((m) -> {
72+
analyzerGuru.getAnalyzerFactoryMatchers().forEach((m) -> {
7273
if (!m.getIsPreciseMagic()) {
7374
b.append(reportable(m));
7475
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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) 2019 Oracle and/or its affiliates. All rights reserved.
22+
*/
23+
package org.opengrok.indexer.analysis;
24+
25+
import java.util.ArrayList;
26+
import java.util.Collections;
27+
import java.util.Comparator;
28+
import java.util.HashMap;
29+
import java.util.List;
30+
import java.util.Map;
31+
import java.util.SortedMap;
32+
import java.util.SortedSet;
33+
import java.util.TreeMap;
34+
import java.util.TreeSet;
35+
36+
/**
37+
* A class wrapping information about used analyzers.
38+
*/
39+
public class AnalyzersInfo {
40+
41+
/**
42+
* Descending string length comparator for magics
43+
*/
44+
private static final Comparator<String> DESCENDING_LENGTH_COMPARATOR =
45+
Comparator.comparingInt(String::length).thenComparing(String::toString);
46+
47+
/**
48+
* Modified when
49+
* {@link AnalyzerFramework#addExtension(String, AnalyzerFactory)}
50+
* or
51+
* {@link AnalyzerFramework#addPrefix(String, AnalyzerFactory)}
52+
* are called to augment the value in {@link AnalyzerGuru#getVersionNo()}.
53+
*/
54+
public final SortedSet<String> customizations;
55+
56+
/**
57+
* Map from file names to analyzer factories.
58+
*/
59+
public final Map<String, AnalyzerFactory> fileNames;
60+
61+
/**
62+
* Map from file extensions to analyzer factories.
63+
*/
64+
public final Map<String, AnalyzerFactory> extensions;
65+
66+
/**
67+
* Map from file prefixes to analyzer factories.
68+
*/
69+
public final Map<String, AnalyzerFactory> prefixes;
70+
71+
/**
72+
* Map from magic strings to analyzer factories.
73+
*/
74+
public final SortedMap<String, AnalyzerFactory> magics;
75+
76+
/**
77+
* List of matcher objects which can be used to determine which analyzer
78+
* factory to use.
79+
*/
80+
public final List<FileAnalyzerFactory.Matcher> matchers;
81+
82+
/**
83+
* List of all registered {@code FileAnalyzerFactory} instances.
84+
*/
85+
public final List<AnalyzerFactory> factories;
86+
87+
/**
88+
* A map of {@link FileAnalyzer#getFileTypeName()} to human readable analyzer name.
89+
*/
90+
public final Map<String, String> fileTypeDescriptions;
91+
92+
/**
93+
* Maps from {@link FileAnalyzer#getFileTypeName()} to
94+
* {@link FileAnalyzerFactory}
95+
*/
96+
public final Map<String, AnalyzerFactory> filetypeFactories;
97+
98+
/**
99+
* Maps from {@link FileAnalyzer#getFileTypeName()} to
100+
* {@link FileAnalyzer#getVersionNo()}
101+
*/
102+
public final Map<String, Long> analyzerVersions;
103+
104+
105+
/**
106+
* Construct an empty analyzers info.
107+
*/
108+
public AnalyzersInfo() {
109+
this(
110+
new TreeSet<>(),
111+
new HashMap<>(),
112+
new HashMap<>(),
113+
new HashMap<>(),
114+
new TreeMap<>(DESCENDING_LENGTH_COMPARATOR),
115+
new ArrayList<>(),
116+
new ArrayList<>(),
117+
new HashMap<>(),
118+
new HashMap<>(),
119+
new HashMap<>()
120+
);
121+
}
122+
123+
/**
124+
* Construct the analyzers info with given collections.
125+
*
126+
* @param customizations the customization keys set
127+
* @param fileNames map of filenames to analyzers factories
128+
* @param extensions map of extensions to analyzers factories
129+
* @param prefixes map of prefixes to analyzers factories
130+
* @param magics map of magics to analyzers factories
131+
* @param matchers a list of matchers for analyzers factories
132+
* @param factories a list of analyzers factories
133+
* @param fileTypeDescriptions map of analyzer names to analyzer descriptions
134+
* @param filetypeFactories map of file type to analyzers factories
135+
* @param analyzerVersions map of analyzer names to analyzer versions
136+
*/
137+
private AnalyzersInfo(
138+
SortedSet<String> customizations,
139+
Map<String, AnalyzerFactory> fileNames,
140+
Map<String, AnalyzerFactory> extensions,
141+
Map<String, AnalyzerFactory> prefixes,
142+
SortedMap<String, AnalyzerFactory> magics,
143+
List<FileAnalyzerFactory.Matcher> matchers,
144+
List<AnalyzerFactory> factories,
145+
Map<String, String> fileTypeDescriptions,
146+
Map<String, AnalyzerFactory> filetypeFactories,
147+
Map<String, Long> analyzerVersions
148+
) {
149+
this.customizations = customizations;
150+
this.fileNames = fileNames;
151+
this.extensions = extensions;
152+
this.prefixes = prefixes;
153+
this.magics = magics;
154+
this.matchers = matchers;
155+
this.factories = factories;
156+
this.fileTypeDescriptions = fileTypeDescriptions;
157+
this.filetypeFactories = filetypeFactories;
158+
this.analyzerVersions = analyzerVersions;
159+
}
160+
161+
/**
162+
* Make the object unmodifiable.
163+
*
164+
* @return a new object reference with all properties wrapped as unmodifiable collections
165+
*/
166+
public AnalyzersInfo freeze() {
167+
return new AnalyzersInfo(
168+
Collections.unmodifiableSortedSet(this.customizations),
169+
Collections.unmodifiableMap(this.fileNames),
170+
Collections.unmodifiableMap(this.extensions),
171+
Collections.unmodifiableMap(this.prefixes),
172+
Collections.unmodifiableSortedMap(this.magics),
173+
Collections.unmodifiableList(this.matchers),
174+
Collections.unmodifiableList(this.factories),
175+
Collections.unmodifiableMap(this.fileTypeDescriptions),
176+
Collections.unmodifiableMap(this.filetypeFactories),
177+
Collections.unmodifiableMap(this.analyzerVersions)
178+
);
179+
}
180+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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) 2019 Oracle and/or its affiliates. All rights reserved.
22+
*/
23+
package org.opengrok.indexer.analysis;
24+
25+
public interface IAnalyzerPlugin {
26+
27+
AnalyzerFactory getFactory();
28+
}

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/archive/BZip2Analyzer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.opengrok.indexer.analysis.AnalyzerGuru;
3636
import org.opengrok.indexer.analysis.FileAnalyzer;
3737
import org.opengrok.indexer.analysis.StreamSource;
38+
import org.opengrok.indexer.configuration.RuntimeEnvironment;
3839

3940
/**
4041
* Analyzes a BZip2 file Created on September 22, 2005
@@ -80,7 +81,7 @@ public void analyze(Document doc, StreamSource src, Writer xrefOut)
8081
String newname = path.substring(0, path.lastIndexOf('.'));
8182
//System.err.println("BZIPPED OF = " + newname);
8283
try (InputStream in = bzSrc.getStream()) {
83-
fa = AnalyzerGuru.getAnalyzer(in, newname);
84+
fa = RuntimeEnvironment.getInstance().getAnalyzerGuru().getAnalyzer(in, newname);
8485
}
8586
if (!(fa instanceof BZip2Analyzer)) {
8687
if (fa.getGenre() == Genre.PLAIN || fa.getGenre() == Genre.XREFABLE) {

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/archive/GZIPAnalyzer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.opengrok.indexer.analysis.AnalyzerGuru;
3939
import org.opengrok.indexer.analysis.FileAnalyzer;
4040
import org.opengrok.indexer.analysis.StreamSource;
41+
import org.opengrok.indexer.configuration.RuntimeEnvironment;
4142
import org.opengrok.indexer.logger.LoggerFactory;
4243

4344
/**
@@ -85,7 +86,7 @@ public void analyze(Document doc, StreamSource src, Writer xrefOut)
8586
String newname = path.substring(0, path.length() - 3);
8687
//System.err.println("GZIPPED OF = " + newname);
8788
try (InputStream gzis = gzSrc.getStream()) {
88-
fa = AnalyzerGuru.getAnalyzer(gzis, newname);
89+
fa = RuntimeEnvironment.getInstance().getAnalyzerGuru().getAnalyzer(gzis, newname);
8990
}
9091
if (fa == null) {
9192
this.g = Genre.DATA;

opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/executables/JarAnalyzer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@
3232
import org.apache.lucene.document.Document;
3333
import org.apache.lucene.document.Field.Store;
3434
import org.opengrok.indexer.analysis.AnalyzerFactory;
35-
import org.opengrok.indexer.analysis.AnalyzerGuru;
3635
import org.opengrok.indexer.analysis.FileAnalyzer;
3736
import org.opengrok.indexer.analysis.OGKTextField;
3837
import org.opengrok.indexer.analysis.StreamSource;
38+
import org.opengrok.indexer.configuration.RuntimeEnvironment;
3939
import org.opengrok.indexer.search.QueryBuilder;
4040
import org.opengrok.indexer.web.Util;
4141

@@ -82,7 +82,7 @@ public void analyze(Document doc, StreamSource src, Writer xrefOut) throws IOExc
8282
fout.write(ename);
8383
fout.write("\n");
8484

85-
AnalyzerFactory fac = AnalyzerGuru.find(ename);
85+
AnalyzerFactory fac = RuntimeEnvironment.getInstance().getAnalyzerGuru().find(ename);
8686
if (fac instanceof JavaClassAnalyzerFactory) {
8787
if (xrefOut != null) {
8888
xrefOut.append("<br/>");

0 commit comments

Comments
 (0)