LUCENE-10261: clean up reflection stuff in luke module and make minor adjustments (#480)

This commit is contained in:
Tomoko Uchida 2021-11-27 15:36:38 +09:00 committed by GitHub
parent 1029651d12
commit 57f695b14d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 20 additions and 258 deletions

View File

@ -37,7 +37,6 @@ import javax.swing.JSplitPane;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.custom.CustomAnalyzer; import org.apache.lucene.analysis.custom.CustomAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.luke.app.desktop.MessageBroker; import org.apache.lucene.luke.app.desktop.MessageBroker;
import org.apache.lucene.luke.app.desktop.components.dialog.analysis.AnalysisChainDialogFactory; import org.apache.lucene.luke.app.desktop.components.dialog.analysis.AnalysisChainDialogFactory;
import org.apache.lucene.luke.app.desktop.components.dialog.analysis.TokenAttributeDialogFactory; import org.apache.lucene.luke.app.desktop.components.dialog.analysis.TokenAttributeDialogFactory;
@ -100,7 +99,6 @@ public final class AnalysisPanelProvider implements AnalysisTabOperator {
this.messageBroker = MessageBroker.getInstance(); this.messageBroker = MessageBroker.getInstance();
this.analysisModel = new AnalysisFactory().newInstance(); this.analysisModel = new AnalysisFactory().newInstance();
analysisModel.createAnalyzerFromClassName(StandardAnalyzer.class.getName());
this.simpleResult = new SimpleAnalyzeResultPanelProvider(tokenAttrDialogFactory).get(); this.simpleResult = new SimpleAnalyzeResultPanelProvider(tokenAttrDialogFactory).get();
this.stepByStepResult = new StepByStepAnalyzeResultPanelProvider(tokenAttrDialogFactory).get(); this.stepByStepResult = new StepByStepAnalyzeResultPanelProvider(tokenAttrDialogFactory).get();

View File

@ -29,12 +29,9 @@ import java.lang.invoke.MethodHandles;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.ButtonGroup; import javax.swing.ButtonGroup;
@ -59,8 +56,8 @@ import org.apache.lucene.luke.app.desktop.util.MessageUtils;
import org.apache.lucene.luke.app.desktop.util.StyleConstants; import org.apache.lucene.luke.app.desktop.util.StyleConstants;
import org.apache.lucene.luke.models.LukeException; import org.apache.lucene.luke.models.LukeException;
import org.apache.lucene.luke.util.LoggerFactory; import org.apache.lucene.luke.util.LoggerFactory;
import org.apache.lucene.luke.util.reflection.ClassScanner; import org.apache.lucene.store.MMapDirectory;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.NIOFSDirectory;
import org.apache.lucene.util.NamedThreadFactory; import org.apache.lucene.util.NamedThreadFactory;
import org.apache.lucene.util.SuppressForbidden; import org.apache.lucene.util.SuppressForbidden;
@ -258,16 +255,7 @@ public final class OpenIndexDialogFactory implements DialogOpener.DialogFactory
} }
private String[] supportedDirImpls() { private String[] supportedDirImpls() {
// supports FS-based built-in implementations return new String[] {MMapDirectory.class.getName(), NIOFSDirectory.class.getName()};
ClassScanner scanner = new ClassScanner("org.apache.lucene.store", getClass().getClassLoader());
Set<Class<? extends FSDirectory>> clazzSet = scanner.scanSubTypes(FSDirectory.class);
List<String> clazzNames = new ArrayList<>();
clazzNames.add(FSDirectory.class.getName());
clazzNames.addAll(clazzSet.stream().map(Class::getName).collect(Collectors.toList()));
String[] result = new String[clazzNames.size()];
return clazzNames.toArray(result);
} }
private JPanel buttons() { private JPanel buttons() {

View File

@ -37,19 +37,19 @@ import javax.swing.JSeparator;
import javax.swing.JTextField; import javax.swing.JTextField;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.custom.CustomAnalyzer; import org.apache.lucene.analysis.custom.CustomAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.luke.app.desktop.components.ComponentOperatorRegistry; import org.apache.lucene.luke.app.desktop.components.ComponentOperatorRegistry;
import org.apache.lucene.luke.app.desktop.components.TabSwitcherProxy; import org.apache.lucene.luke.app.desktop.components.TabSwitcherProxy;
import org.apache.lucene.luke.app.desktop.components.TabbedPaneProvider; import org.apache.lucene.luke.app.desktop.components.TabbedPaneProvider;
import org.apache.lucene.luke.app.desktop.util.FontUtils; import org.apache.lucene.luke.app.desktop.util.FontUtils;
import org.apache.lucene.luke.app.desktop.util.MessageUtils; import org.apache.lucene.luke.app.desktop.util.MessageUtils;
import org.apache.lucene.luke.models.analysis.AnalysisFactory;
/** Provider of the Analyzer pane */ /** Provider of the Analyzer pane */
public final class AnalyzerPaneProvider implements AnalyzerTabOperator { public final class AnalyzerPaneProvider implements AnalyzerTabOperator {
private final TabSwitcherProxy tabSwitcher; private final TabSwitcherProxy tabSwitcher;
private final JLabel analyzerNameLbl = new JLabel(StandardAnalyzer.class.getName()); private final JLabel analyzerNameLbl = new JLabel();
private final JList<String> charFilterList = new JList<>(); private final JList<String> charFilterList = new JList<>();
@ -59,6 +59,8 @@ public final class AnalyzerPaneProvider implements AnalyzerTabOperator {
public AnalyzerPaneProvider() { public AnalyzerPaneProvider() {
this.tabSwitcher = TabSwitcherProxy.getInstance(); this.tabSwitcher = TabSwitcherProxy.getInstance();
this.analyzerNameLbl.setText(
new AnalysisFactory().newInstance().currentAnalyzer().getClass().getName());
ComponentOperatorRegistry.getInstance().register(AnalyzerTabOperator.class, this); ComponentOperatorRegistry.getInstance().register(AnalyzerTabOperator.class, this);
} }

View File

@ -50,7 +50,7 @@ import org.apache.lucene.util.IOUtils;
/** Default implementation of {@link AnalysisImpl} */ /** Default implementation of {@link AnalysisImpl} */
public final class AnalysisImpl implements Analysis { public final class AnalysisImpl implements Analysis {
private Analyzer analyzer; private Analyzer analyzer = defaultAnalyzer();
@Override @Override
public void addExternalJars(List<String> jarFiles) { public void addExternalJars(List<String> jarFiles) {
@ -152,6 +152,14 @@ public final class AnalysisImpl implements Analysis {
} }
} }
private Analyzer defaultAnalyzer() {
try {
return CustomAnalyzer.builder().withTokenizer("standard").build();
} catch (IOException e) {
throw new LukeException("Failed to build custom analyzer.", e);
}
}
@Override @Override
public Analyzer buildCustomAnalyzer(CustomAnalyzerConfig config) { public Analyzer buildCustomAnalyzer(CustomAnalyzerConfig config) {
Objects.requireNonNull(config); Objects.requireNonNull(config);

View File

@ -1,113 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.luke.util.reflection;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.util.LoggerFactory;
import org.apache.lucene.util.NamedThreadFactory;
/** Utility class for scanning class files in jars. */
public class ClassScanner {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final String packageName;
private final ClassLoader[] classLoaders;
public ClassScanner(String packageName, ClassLoader... classLoaders) {
this.packageName = packageName;
this.classLoaders = classLoaders;
}
public <T> Set<Class<? extends T>> scanSubTypes(Class<T> superType) {
final int numThreads = Runtime.getRuntime().availableProcessors();
List<SubtypeCollector<T>> collectors = new ArrayList<>();
for (int i = 0; i < numThreads; i++) {
collectors.add(new SubtypeCollector<T>(superType, packageName, classLoaders));
}
try {
List<URL> urls = getJarUrls();
for (int i = 0; i < urls.size(); i++) {
collectors.get(i % numThreads).addUrl(urls.get(i));
}
ExecutorService executorService =
Executors.newFixedThreadPool(numThreads, new NamedThreadFactory("scanner-scan-subtypes"));
for (SubtypeCollector<T> collector : collectors) {
executorService.submit(collector);
}
try {
executorService.shutdown();
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (
@SuppressWarnings("unused")
InterruptedException e) {
} finally {
executorService.shutdownNow();
}
Set<Class<? extends T>> types = new HashSet<>();
for (SubtypeCollector<T> collector : collectors) {
types.addAll(collector.getTypes());
}
return types;
} catch (IOException e) {
log.error("Cannot load jar file entries", e);
}
return Collections.emptySet();
}
private List<URL> getJarUrls() throws IOException {
List<URL> urls = new ArrayList<>();
String resourceName = resourceName(packageName);
for (ClassLoader loader : classLoaders) {
for (Enumeration<URL> e = loader.getResources(resourceName); e.hasMoreElements(); ) {
URL url = e.nextElement();
// extract jar file path from the resource name
int index = url.getPath().lastIndexOf(".jar");
if (index > 0) {
String path = url.getPath().substring(0, index + 4);
urls.add(new URL(path));
}
}
}
return urls;
}
private static String resourceName(String packageName) {
if (packageName == null || packageName.equals("")) {
return packageName;
}
return packageName.replace('.', '/');
}
}

View File

@ -1,102 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.luke.util.reflection;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.luke.util.LoggerFactory;
final class SubtypeCollector<T> implements Runnable {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final Set<URL> urls = new HashSet<>();
private final Class<T> superType;
private final String packageName;
private final ClassLoader[] classLoaders;
private final Set<Class<? extends T>> types = new HashSet<>();
SubtypeCollector(Class<T> superType, String packageName, ClassLoader... classLoaders) {
this.superType = superType;
this.packageName = packageName;
this.classLoaders = classLoaders;
}
void addUrl(URL url) {
urls.add(url);
}
Set<Class<? extends T>> getTypes() {
return Set.copyOf(types);
}
@Override
public void run() {
for (URL url : urls) {
try (JarInputStream jis = new JarInputStream(url.openStream())) {
// iterate all zip entry in the jar
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
String name = entry.getName();
if (name.endsWith(".class")
&& name.indexOf('$') < 0
&& !name.contains("package-info")
&& !name.startsWith("META-INF")) {
String fqcn = convertToFQCN(name);
if (!fqcn.startsWith(packageName)) {
continue;
}
for (ClassLoader cl : classLoaders) {
try {
Class<?> clazz = Class.forName(fqcn, false, cl);
if (superType.isAssignableFrom(clazz) && !Objects.equals(superType, clazz)) {
types.add(clazz.asSubclass(superType));
}
break;
} catch (
@SuppressWarnings("unused")
Throwable e) {
}
}
}
}
} catch (IOException e) {
log.error("Cannot load jar {}", url, e);
}
}
}
private static String convertToFQCN(String name) {
if (name == null || name.equals("")) {
return name;
}
int index = name.lastIndexOf(".class");
return name.replace('/', '.').substring(0, index);
}
}

View File

@ -1,19 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** Utilities for reflections */
package org.apache.lucene.luke.util.reflection;

View File

@ -125,11 +125,11 @@ public class TestAnalysisImpl extends LuceneTestCase {
assertNotNull(tokens); assertNotNull(tokens);
} }
@Test(expected = LukeException.class) public void testAnalyze_default() {
public void testAnalyze_not_set() {
AnalysisImpl analysis = new AnalysisImpl(); AnalysisImpl analysis = new AnalysisImpl();
String text = "This test must fail."; String text = "Apache Lucene";
analysis.analyze(text); List<Analysis.Token> tokens = analysis.analyze(text);
assertNotNull(tokens);
} }
@Test(expected = LukeException.class) @Test(expected = LukeException.class)