You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ma...@apache.org on 2018/05/16 21:27:38 UTC
[incubator-netbeans] branch master updated: Maven Indexing
Optimizations (#537)
This is an automated email from the ASF dual-hosted git repository.
matthiasblaesing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new 434b89a Maven Indexing Optimizations (#537)
434b89a is described below
commit 434b89a2ad029abf11cd445b20c2e089f0b3626a
Author: Tim Boudreau <ni...@gmail.com>
AuthorDate: Wed May 16 17:27:34 2018 -0400
Maven Indexing Optimizations (#537)
* Maven indexer optimizations
* Remove println from test
* Actually set the ThreadLocal
* Avoid array creation
* Use new Apache license header, not old Oracle one
* Fix other license header - was unsaved on last commit
* More nuanced JDK package detection; limits path element count to 3, to balance performance requirements against absolute accuracy, since com/sun or java/ or javax/ packages are a micro-probability corner case within the Maven universe - you don't get the JDK from a Maven repository, and this is highly performance-sensitive code
* Remove comment
* Ensure stream is fully read
* Integrating Matthias Bläsing's patch for MatchWords
* Add description to FastScanner; .sha1 files not needed to index; use final fields; fix line comment typo
* Remove now unneeded warning suppression
---
.../maven/indexer/ClassDependencyIndexCreator.java | 182 +++++++++++++++------
.../modules/maven/indexer/FastScanner.java | 137 ++++++++++++++++
.../netbeans/modules/maven/indexer/MatchWords.java | 111 +++++++++++++
.../maven/indexer/NexusRepositoryIndexerImpl.java | 3 +-
.../indexer/ClassDependencyIndexCreatorTest.java | 12 +-
.../modules/maven/indexer/MatchWordsTest.java | 42 +++++
6 files changed, 436 insertions(+), 51 deletions(-)
diff --git a/maven.indexer/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreator.java b/maven.indexer/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreator.java
index 931df34..aef7b28 100644
--- a/maven.indexer/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreator.java
+++ b/maven.indexer/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreator.java
@@ -20,9 +20,6 @@
package org.netbeans.modules.maven.indexer;
import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInput;
-import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -33,11 +30,12 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
@@ -66,7 +64,6 @@ import org.netbeans.modules.classfile.ClassFile;
import org.netbeans.modules.classfile.ClassName;
import org.netbeans.modules.maven.indexer.api.NBVersionInfo;
import org.netbeans.modules.maven.indexer.api.RepositoryQueries.ClassUsage;
-import org.openide.filesystems.FileUtil;
/**
* Scans classes in (local) JARs for their Java dependencies.
@@ -86,7 +83,8 @@ class ClassDependencyIndexCreator extends AbstractIndexCreator {
/** class/in/this/Jar -> [foreign/Class, other/foreign/Nested$Class] */
private Map<String,Set<String>> classDeps;
- @Override public void populateArtifactInfo(ArtifactContext context) throws IOException {
+ @Override
+ public void populateArtifactInfo(ArtifactContext context) throws IOException {
classDeps = null;
ArtifactInfo ai = context.getArtifactInfo();
if (ai.getClassifier() != null) {
@@ -100,18 +98,24 @@ class ClassDependencyIndexCreator extends AbstractIndexCreator {
LOG.log(Level.FINER, "no artifact for {0}", ai); // not a big deal, maybe just *.pom (or *.pom + *.nbm) here
return;
}
+ if (jar.length() == 0) {
+ LOG.log(Level.FINER, "zero length jar for {0}", ai); // Don't try to index zero length files
+ return;
+ }
String packaging = ai.getPackaging();
if (packaging == null || (!packaging.equals("jar") && !isArchiveFile(jar))) {
LOG.log(Level.FINE, "skipping artifact {0} with unrecognized packaging based on {1}", new Object[] {ai, jar});
return;
}
LOG.log(Level.FINER, "reading {0}", jar);
- Map<String, byte[]> classfiles = read(jar);
- classDeps = new HashMap<String, Set<String>>();
- Set<String> classes = classfiles.keySet();
- for (Map.Entry<String, byte[]> entry : classfiles.entrySet()) {
- addDependenciesToMap(entry.getKey(), entry.getValue(), classDeps, classes, jar);
- }
+ classDeps = new HashMap<>();
+ read(jar, (String name, InputStream stream, Set<String> classes) -> {
+ try {
+ addDependenciesToMap(name, stream, classDeps, classes, jar);
+ } catch (IOException ex) {
+ LOG.log(Level.INFO, "Exception indexing " + jar, ex);
+ }
+ });
}
// adapted from FileUtil, since we do not want to have to use FileObject's here
@@ -213,6 +217,50 @@ class ClassDependencyIndexCreator extends AbstractIndexCreator {
return referrers;
}
+ static final Predicate<String> JDK_CLASS_TEST = new MatchWords(new String[]{
+ "apple/applescript", "apple/laf", "apple/launcher", "apple/security",
+ "com/apple/concurrent", "com/apple/eawt", "com/apple/eio", "com/apple/laf", "com/oracle/net",
+ "com/oracle/nio", "com/oracle/util", "com/oracle/webservices", "com/oracle/xmlns",
+ "com/sun/accessibility", "com/sun/activation", "com/sun/awt", "com/sun/beans", "com/sun/corba",
+ "com/sun/demo", "com/sun/image", "com/sun/imageio", "com/sun/istack", "com/sun/java",
+ "com/sun/java_cup", "com/sun/jmx", "com/sun/jndi", "com/sun/management", "com/sun/media",
+ "com/sun/naming", "com/sun/net", "com/sun/nio", "com/sun/org", "com/sun/rmi", "com/sun/rowset",
+ "com/sun/security", "com/sun/swing", "com/sun/tracing", "com/sun/xml", "java/applet", "java/awt",
+ "java/awt/color", "java/awt/datatransfer", "java/awt/dnd", "java/awt/event", "java/awt/font",
+ "java/awt/geom", "java/awt/im", "java/awt/image", "java/awt/peer", "java/awt/print",
+ "java/beans", "java/beans/beancontext", "java/io", "java/lang", "java/lang/annotation",
+ "java/lang/instrument", "java/lang/invoke", "java/lang/management", "java/lang/ref",
+ "java/lang/reflect", "java/math", "java/net", "java/nio", "java/nio/channels", "java/nio/charset",
+ "java/nio/file", "java/rmi", "java/rmi/activation", "java/rmi/dgc", "java/rmi/registry",
+ "java/rmi/server", "java/security", "java/security/acl", "java/security/cert",
+ "java/security/interfaces", "java/security/spec", "java/sql", "java/text", "java/text/spi", "java/time",
+ "java/time/chrono", "java/time/format", "java/time/temporal", "java/time/zone", "java/util",
+ "java/util/concurrent", "java/util/function", "java/util/jar", "java/util/logging",
+ "java/util/prefs", "java/util/regex", "java/util/spi", "java/util/stream", "java/util/zip",
+ "javax/accessibility", "javax/activation", "javax/activity", "javax/annotation",
+ "javax/annotation/processing", "javax/imageio", "javax/imageio/event", "javax/imageio/metadata",
+ "javax/imageio/plugins", "javax/imageio/spi", "javax/imageio/stream", "javax/jws", "javax/jws/soap",
+ "javax/lang/model", "javax/management", "javax/management/loading",
+ "javax/management/modelmbean", "javax/management/monitor", "javax/management/openmbean",
+ "javax/management/relation", "javax/management/remote", "javax/management/timer", "javax/naming",
+ "javax/naming/directory", "javax/naming/event", "javax/naming/ldap", "javax/naming/spi", "javax/net",
+ "javax/net/ssl", "javax/print", "javax/print/attribute", "javax/print/event", "javax/rmi",
+ "javax/rmi/CORBA", "javax/rmi/ssl", "javax/script", "javax/security/auth",
+ "javax/security/cert", "javax/security/sasl", "javax/smartcardio", "javax/sound/midi",
+ "javax/sound/sampled", "javax/sql", "javax/sql/rowset", "javax/swing", "javax/swing/border",
+ "javax/swing/colorchooser", "javax/swing/event", "javax/swing/filechooser", "javax/swing/plaf",
+ "javax/swing/table", "javax/swing/text", "javax/swing/tree", "javax/swing/undo", "javax/tools",
+ "javax/transaction", "javax/transaction/xa", "javax/xml", "javax/xml/bind", "javax/xml/crypto",
+ "javax/xml/datatype", "javax/xml/namespace", "javax/xml/parsers", "javax/xml/soap",
+ "javax/xml/stream", "javax/xml/transform", "javax/xml/validation", "javax/xml/ws",
+ "javax/xml/xpath", "jdk/internal/cmm", "jdk/internal/instrumentation", "jdk/internal/org",
+ "jdk/internal/util", "jdk/management/cmm", "jdk/management/resource", "jdk/net",
+ "jdk/xml/internal", "org/ietf/jgss", "org/jcp/xml", "org/omg/CORBA", "org/omg/CORBA_2_3",
+ "org/omg/CosNaming", "org/omg/Dynamic", "org/omg/DynamicAny", "org/omg/IOP", "org/omg/Messaging",
+ "org/omg/PortableInterceptor", "org/omg/PortableServer", "org/omg/SendingContext", "org/omg/stub",
+ "org/w3c/dom", "org/xml/sax"
+ });
+
/**
* @param referrer a referring class, as {@code pkg/Outer$Inner}
* @param data its bytecode
@@ -220,32 +268,60 @@ class ClassDependencyIndexCreator extends AbstractIndexCreator {
* @param siblings other referring classes in the same artifact (including this one), as {@code pkg/Outer$Inner}
* @param jar the jar file, for diagnostics
*/
- private static void addDependenciesToMap(String referrer, byte[] data, Map<String, Set<String>> depsMap, Set<String> siblings, File jar) throws IOException {
- ClassLoader jre = ClassLoader.getSystemClassLoader().getParent();
+ private static void addDependenciesToMap(String referrer, InputStream data, Map<String, Set<String>> depsMap, Set<String> siblings, File jar) throws IOException {
int shell = referrer.indexOf('$', referrer.lastIndexOf('/') + 1);
String referrerTopLevel = shell == -1 ? referrer : referrer.substring(0, shell);
- for (String referee : dependencies(data, referrer, jar)) {
+ for (String referee : dependencies(data, jar)) {
+ if (referrer.equals(referee)) {
+ continue;
+ }
if (siblings.contains(referee)) {
continue; // in same JAR, not interesting
}
- try {
- jre.loadClass(referee.replace('/', '.')); // XXX ought to cache this result
- continue; // in JRE, not interesting
- } catch (ClassNotFoundException x) {
+ if (JDK_CLASS_TEST.test(referee)) {
+ continue;
}
Set<String> referees = depsMap.get(referrerTopLevel);
if (referees == null) {
- referees = new TreeSet<String>();
+ referees = new HashSet<>();
depsMap.put(referrerTopLevel, referees);
}
referees.add(referee);
}
}
- static Map<String,byte[]> read(File jar) throws IOException {
- JarFile jf = new JarFile(jar, false);
- try {
- Map<String, byte[]> classfiles = new TreeMap<String, byte[]>();
+ @FunctionalInterface
+ interface JarClassEntryConsumer {
+
+ void accept(String name, InputStream classData, Set<String> siblings) throws IOException;
+ }
+
+ // XXX in unit tests, indexing is always single-threaded,
+ // in which case the byte array can be a field instead of
+ // a thread local. Not clear if that is the case in the IDE.
+ final ThreadLocal<byte[]> BYTES = new ThreadLocal<>();
+ // A reasonable base array size that will accommodate typical
+ // class files, to avoid reallocating more than necessary
+ private static final int MIN_ARRAY_SIZE = 16384;
+
+ byte[] bytes(int size) {
+ // There is a pretty significant performance benefit
+ // to not allocating vast numbers of byte arrays
+ byte[] result = BYTES.get();
+ if (result == null || result.length < size) {
+ result = new byte[Math.max(MIN_ARRAY_SIZE, size)];
+ BYTES.set(result);
+ }
+ return result;
+ }
+
+ void read(File jar, JarClassEntryConsumer consumer) throws IOException {
+ Set<String> classNames = new HashSet<>();
+ try (JarFile jf = new JarFile(jar, false)) {
+ // XXX the original code ignores siblings by first having a list
+ // of the class names. Getting this before processing JAR entries
+ // means iterating the zip index twice. Not horrible, but would
+ // be nice to avoid it
Enumeration<JarEntry> e = jf.entries();
while (e.hasMoreElements()) {
JarEntry entry = e.nextElement();
@@ -254,29 +330,44 @@ class ClassDependencyIndexCreator extends AbstractIndexCreator {
continue;
}
String clazz = name.substring(0, name.length() - 6);
- ByteArrayOutputStream baos = new ByteArrayOutputStream(Math.max((int) entry.getSize(), 0));
- InputStream is = jf.getInputStream(entry);
- try {
- FileUtil.copy(is, baos);
- } finally {
- is.close();
+ classNames.add(clazz);
+ }
+ e = jf.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ String name = entry.getName();
+ if (!name.endsWith(".class")) {
+ continue;
+ }
+ int size = Math.max((int) entry.getSize(), 0);
+ if (size > 0) {
+ // Parsing is considerably faster if the data is preloaded
+ // into a byte array, likely due to random access
+ byte[] target = bytes(size);
+ try (InputStream in = jf.getInputStream(entry)) {
+ int pos = 0;
+ int count = 0;
+ while (count != -1 && pos < size) {
+ count = in.read(target, pos, size - pos);
+ pos += count == -1 ? 0 : count;
+ }
+ }
+ try (InputStream in = new ByteArrayInputStream(target, 0, size)) {
+ String clazz = name.substring(0, name.length() - 6);
+ consumer.accept(clazz, in, classNames);
+ }
}
- classfiles.put(clazz, baos.toByteArray());
}
- return classfiles;
} catch (SecurityException x) {
throw new IOException(x);
- } finally {
- jf.close();
}
}
// adapted from org.netbeans.nbbuild.VerifyClassLinkage
- private static Set<String> dependencies(byte[] data, String clazz, File jar) throws IOException {
- Set<String> result = new TreeSet<String>();
- DataInputStream input = new DataInputStream(new ByteArrayInputStream(data));
- ClassFile cf = new ClassFile(input);
-
+ private static Collection<String> dependencies(InputStream data, File jar) throws IOException {
+ Set<String> result = new HashSet<String>();
+ ClassFile cf = new ClassFile(data);
+
Set<ClassName> cl = cf.getAllClassNames();
for (ClassName className : cl) {
result.add(className.getInternalName());
@@ -284,15 +375,10 @@ class ClassDependencyIndexCreator extends AbstractIndexCreator {
return result;
}
- private static void skip(DataInput input, int bytes) throws IOException {
- int skipped = input.skipBytes(bytes);
- if (skipped != bytes) {
- throw new IOException("Truncated class file");
- }
- }
-
- @Override public Collection<IndexerField> getIndexerFields() {
- return Arrays.asList(FLD_NB_DEPENDENCY_CLASS);
+ static final List<IndexerField> INDEXER_FIELDS = Collections.singletonList(FLD_NB_DEPENDENCY_CLASS);
+ @Override
+ public Collection<IndexerField> getIndexerFields() {
+ return INDEXER_FIELDS;
}
/**
diff --git a/maven.indexer/src/org/netbeans/modules/maven/indexer/FastScanner.java b/maven.indexer/src/org/netbeans/modules/maven/indexer/FastScanner.java
new file mode 100644
index 0000000..5b15030
--- /dev/null
+++ b/maven.indexer/src/org/netbeans/modules/maven/indexer/FastScanner.java
@@ -0,0 +1,137 @@
+/*
+ * 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.netbeans.modules.maven.indexer;
+
+import com.google.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.maven.index.ArtifactContext;
+import org.apache.maven.index.ArtifactContextProducer;
+import org.apache.maven.index.Scanner;
+import org.apache.maven.index.ScanningRequest;
+import org.apache.maven.index.ScanningResult;
+import org.apache.maven.index.context.IndexingContext;
+
+/**
+ * Alternative to Maven's DefaultScanner which ignores files NetBeans will not
+ * be interested in indexing; and publishes scanning requests incrementally,
+ * per-directory, rather than first collecting a tree's worth of artifacts.
+ *
+ * @author Tim Boudreau
+ */
+public class FastScanner
+ implements Scanner {
+
+ private final ArtifactContextProducer artifactContextProducer;
+ private static final Logger LOG = Logger.getLogger(FastScanner.class.getName());
+
+ @Inject
+ public FastScanner(ArtifactContextProducer artifactContextProducer) {
+ this.artifactContextProducer = artifactContextProducer;
+ }
+
+ public ScanningResult scan(ScanningRequest request) {
+ request.getArtifactScanningListener().scanningStarted(request.getIndexingContext());
+ ScanningResult result = new ScanningResult(request);
+ try {
+ scanDirectory(request.getStartingDirectory().toPath(), request);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, "Scanning failed", ex);
+ } finally {
+ request.getArtifactScanningListener().scanningFinished(request.getIndexingContext(), result);
+ }
+
+ return result;
+ }
+
+ private void scanDirectory(Path dir, ScanningRequest request) throws IOException {
+ if (dir == null) {
+ return;
+ }
+ Files.walkFileTree(dir, new FileVisitor<Path>() {
+ private final Set<Path> poms = new HashSet<>();
+ private final Set<Path> artifacts = new HashSet<>();
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ poms.clear();
+ artifacts.clear();
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ String nm = file.getFileName().toString();
+ if (nm.endsWith(".pom")) {
+ poms.add(file);
+ // txt and sha1 are needed for tests to pass, but not likely useful
+ // in NetBeans, and will impact performance
+ } else if (nm.endsWith(".jar") || nm.endsWith(".nbm") || nm.endsWith(".txt") || nm.endsWith(".xml")) {
+ artifacts.add(file);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ LOG.log(Level.INFO, "Visit failed: " + file, exc);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ // Ensure JARs are procssed before POMs - see comments on
+ // DefaultScanner's nested comparator class for why
+ try {
+ if (!artifacts.isEmpty()) {
+ for (Path jar : artifacts) {
+ processFile(jar.toFile(), request);
+ }
+ }
+ if (!poms.isEmpty()) {
+ for (Path pom : poms) {
+ processFile(pom.toFile(), request);
+ }
+ }
+ } catch (Exception e) {
+ LOG.log(Level.INFO, "Exception indexing " + artifacts + ", " + poms, e);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ private void processFile(File file, ScanningRequest request) {
+ IndexingContext context = request.getIndexingContext();
+ ArtifactContext ac = artifactContextProducer.getArtifactContext(context, file);
+
+ if (ac != null) {
+ request.getArtifactScanningListener().artifactDiscovered(ac);
+ }
+ }
+}
diff --git a/maven.indexer/src/org/netbeans/modules/maven/indexer/MatchWords.java b/maven.indexer/src/org/netbeans/modules/maven/indexer/MatchWords.java
new file mode 100644
index 0000000..cff7000
--- /dev/null
+++ b/maven.indexer/src/org/netbeans/modules/maven/indexer/MatchWords.java
@@ -0,0 +1,111 @@
+/*
+ * 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.netbeans.modules.maven.indexer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * Given multiple strings, this {@link Predicate} tests positive, if one or
+ * multiple of the strings are prefixes of the string, that is tested.
+ *
+ * @author Tim Boudreau
+ */
+final class MatchWords implements Predicate<String> {
+
+ private final List<MatchState> matchers = new ArrayList<>();
+ private ThreadLocal<MatchState[]> local = new ThreadLocal<>();
+
+ MatchWords(String[] strings) {
+ for (String s : strings) {
+ matchers.add(new MatchState(s));
+ }
+ }
+
+ private MatchState[] matchers() {
+ MatchState[] result = local.get();
+ if (result == null) {
+ result = new MatchState[matchers.size()];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = matchers.get(i).copy();
+ }
+ local.set(result);
+ }
+ return result;
+ }
+
+ @Override
+ public boolean test(String t) {
+ int max = t.length();
+ MatchState[] mtchrs = matchers();
+ for (MatchState mtchr : mtchrs) {
+ mtchr.reset();
+ }
+ for (int i = 0; i < max; i++) {
+ char c = t.charAt(i);
+ for (int j = 0; j < mtchrs.length; j++) {
+ mtchrs[j].check(c);
+ if (mtchrs[j].isMatched()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static final class MatchState {
+
+ private final char[] what;
+ private int matched = 0;
+ private boolean failed = false;
+
+ MatchState(String what) {
+ this.what = what.toCharArray();
+ }
+
+ MatchState(char[] what) {
+ this.what = what;
+ }
+
+ public MatchState copy() {
+ return new MatchState(what);
+ }
+
+ private void reset() {
+ matched = 0;
+ failed = false;
+ }
+
+ boolean isMatched() {
+ return matched >= what.length;
+ }
+
+ void check(char c) {
+ if (failed || isMatched()) {
+ return;
+ }
+ if (what[matched] == c) {
+ matched++;
+ } else {
+ failed = true;
+ }
+ }
+ }
+}
diff --git a/maven.indexer/src/org/netbeans/modules/maven/indexer/NexusRepositoryIndexerImpl.java b/maven.indexer/src/org/netbeans/modules/maven/indexer/NexusRepositoryIndexerImpl.java
index 7affa26..0c46109 100644
--- a/maven.indexer/src/org/netbeans/modules/maven/indexer/NexusRepositoryIndexerImpl.java
+++ b/maven.indexer/src/org/netbeans/modules/maven/indexer/NexusRepositoryIndexerImpl.java
@@ -41,7 +41,6 @@ import java.util.zip.ZipError;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.QueryParser;
-import org.apache.maven.index.expr.SearchTyped;
import org.codehaus.plexus.PlexusConstants;
import org.apache.lucene.search.*;
import org.apache.lucene.store.FSDirectory;
@@ -252,10 +251,10 @@ public class NexusRepositoryIndexerImpl implements RepositoryIndexerImplementati
desc.addRequirement(req);
embedder.addComponentDescriptor(desc);
indexer = embedder.lookup(Indexer.class);
- scanner = embedder.lookup(org.apache.maven.index.Scanner.class);
searcher = embedder.lookup(SearchEngine.class);
remoteIndexUpdater = embedder.lookup(IndexUpdater.class);
contextProducer = embedder.lookup(ArtifactContextProducer.class);
+ scanner = new FastScanner(contextProducer);
inited = true;
} catch (Exception x) {
Exceptions.printStackTrace(x);
diff --git a/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreatorTest.java b/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreatorTest.java
index a61eb2a..f404a4b 100644
--- a/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreatorTest.java
+++ b/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/ClassDependencyIndexCreatorTest.java
@@ -19,12 +19,17 @@
package org.netbeans.modules.maven.indexer;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
import org.netbeans.modules.maven.indexer.api.RepositoryQueries.ClassUsage;
+import org.openide.filesystems.FileUtil;
import org.openide.util.test.JarBuilder;
import org.openide.util.test.TestFileUtils;
@@ -93,7 +98,12 @@ public class ClassDependencyIndexCreatorTest extends NexusTestBase {
File jar = TestFileUtils.writeZipFile(new File(getWorkDir(), "x.jar"),
// XXX failed to produce a manifest that would generate a SecurityException if loaded with verify=true
"pkg/Clazz.class:ABC");
- Map<String,byte[]> content = ClassDependencyIndexCreator.read(jar);
+ Map<String, byte[]> content = new TreeMap<>();
+ new ClassDependencyIndexCreator().read(jar, (String name, InputStream classData, Set<String> siblings) -> {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ FileUtil.copy(classData, out);
+ content.put(name, out.toByteArray());
+ });
assertEquals("[pkg/Clazz]", content.keySet().toString());
assertEquals("[65, 66, 67]", Arrays.toString(content.get("pkg/Clazz")));
}
diff --git a/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/MatchWordsTest.java b/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/MatchWordsTest.java
new file mode 100644
index 0000000..dd57182
--- /dev/null
+++ b/maven.indexer/test/unit/src/org/netbeans/modules/maven/indexer/MatchWordsTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.netbeans.modules.maven.indexer;
+
+import java.util.function.Predicate;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class MatchWordsTest {
+
+ @Test
+ public void testPositiveMatches() {
+ MatchWords mw = new MatchWords(new String[]{"javax/swing", "javax/sql"});
+ assertTrue(mw.test("javax/swing"));
+ assertTrue(mw.test("javax/sql"));
+ assertTrue(mw.test("javax/swing/test"));
+ assertTrue(mw.test("javax/sql/test/more/depth"));
+ }
+
+ @Test
+ public void testNegativeMatches() {
+ MatchWords mw = new MatchWords(new String[]{"javax/swing", "javax/sql"});
+ assertFalse(mw.test("javax/swin"));
+ assertFalse(mw.test("javax/I_SHOULD_NOT_MATCH/sql"));
+ }
+}
--
To stop receiving notification emails like this one, please contact
matthiasblaesing@apache.org.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists