blob: be6191e048cf2da8a8224705b81ab4e4f3063938 [file] [log] [blame]
/*
* 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.parsing.spi.indexing.support;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.swing.event.ChangeListener;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.editor.mimelookup.MimePath;
import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.junit.MockServices;
import org.netbeans.junit.NbTestCase;
import org.netbeans.modules.parsing.api.Embedding;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.parsing.api.ResultIterator;
import org.netbeans.modules.parsing.api.Snapshot;
import org.netbeans.modules.parsing.api.Task;
import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.api.indexing.IndexingManager;
import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
import org.netbeans.modules.parsing.impl.indexing.FooPathRecognizer;
import org.netbeans.modules.parsing.impl.indexing.IndexingTestBase;
import org.netbeans.modules.parsing.impl.indexing.RepositoryUpdaterTest;
import org.netbeans.modules.parsing.impl.indexing.SPIAccessor;
import org.netbeans.modules.parsing.impl.indexing.lucene.LayeredDocumentIndex;
import org.netbeans.modules.parsing.impl.indexing.lucene.LuceneIndexFactory;
import org.netbeans.modules.parsing.spi.EmbeddingProvider;
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.modules.parsing.spi.Parser;
import org.netbeans.modules.parsing.spi.ParserFactory;
import org.netbeans.modules.parsing.spi.SchedulerTask;
import org.netbeans.modules.parsing.spi.SourceModificationEvent;
import org.netbeans.modules.parsing.spi.TaskFactory;
import org.netbeans.modules.parsing.spi.indexing.Context;
import org.netbeans.modules.parsing.spi.indexing.EmbeddingIndexer;
import org.netbeans.modules.parsing.spi.indexing.EmbeddingIndexerFactory;
import org.netbeans.modules.parsing.spi.indexing.Indexable;
import org.netbeans.modules.parsing.spi.indexing.PathRecognizer;
import org.netbeans.spi.java.classpath.ClassPathProvider;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.Pair;
import org.openide.util.test.TestFileUtils;
/**
*
* @author Tomas Zezula
*/
public class QuerySupportLifeLock230220Test extends IndexingTestBase {
private FileObject sources;
private FileObject srcFile;
private ClassPath scp;
public QuerySupportLifeLock230220Test(@NonNull final String name) {
super(name);
}
@Override
protected void getAdditionalServices(List<Class> clazz) {
super.getAdditionalServices(clazz);
clazz.add(ClassPathProviderImpl.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
clearWorkDir();
final FileObject wd = FileUtil.toFileObject(getWorkDir());
final FileObject cache = FileUtil.createFolder(wd, "cache"); //NOI18N
CacheFolder.setCacheFolder(cache);
MockMimeLookup.setInstances(
MimePath.get(FooPathRecognizer.FOO_MIME),
new FooParser.Factory(),
new EmbEmbeddingProvider.Factory(),
new FooIndexer.Factory());
MockMimeLookup.setInstances(
MimePath.get(EmbeddedPathRecognizer.EMB_MIME),
new EmbParser.Factory(),
new EmbIndexer.Factory());
sources = FileUtil.createFolder(wd, "src"); //NOI18N
srcFile = FileUtil.createData(sources, "file.foo"); //NOI18N
scp = ClassPathSupport.createClassPath(sources);
final ClassPathProviderImpl cppImpl = Lookup.getDefault().lookup(ClassPathProviderImpl.class);
cppImpl.roots2cp = Pair.<FileObject[],ClassPath>of(
new FileObject[]{sources},
scp);
TestFileUtils.writeFile(
FileUtil.toFile(srcFile),
"class {Lookup} class {ProjectManager} class {FileOwnerQuery}"); //NOI18N
FileUtil.setMIMEType("foo", FooPathRecognizer.FOO_MIME); //NOI18N
RepositoryUpdaterTest.setMimeTypes(
FooPathRecognizer.FOO_MIME,
EmbeddedPathRecognizer.EMB_MIME);
RepositoryUpdaterTest.waitForRepositoryUpdaterInit();
}
public void testLifeLock230220() throws Exception {
IndexingManager.getDefault().refreshIndexAndWait(sources.toURL(), null);
final String indexerId = SPIAccessor.getInstance().getIndexerPath(
EmbIndexer.EMB_INDEXER_NAME,
EmbIndexer.EMB_INDEXER_VERSION);
final FileObject cacheFolder = CacheFolder.getDataFolder(sources.toURL());
assertNotNull(cacheFolder);
final FileObject indexFolder = cacheFolder.getFileObject(indexerId);
assertNotNull(indexFolder);
final LayeredDocumentIndex index = LuceneIndexFactory.getDefault().getIndex(indexFolder);
index.markKeyDirty(FileUtil.getRelativePath(sources, srcFile));
final QuerySupport qs = QuerySupport.forRoots(EmbIndexer.EMB_INDEXER_NAME, EmbIndexer.EMB_INDEXER_VERSION, sources);
final Collection<? extends IndexResult> result = qs.query(
"key", //NOI18N
"", //NOI18N
QuerySupport.Kind.PREFIX,
"key"); //NOI18N
}
public static final class FooParser extends Parser {
private Snapshot snapshot;
@Override
public void parse(Snapshot snapshot, Task task, SourceModificationEvent event) throws ParseException {
this.snapshot = snapshot;
}
@Override
public Result getResult(Task task) throws ParseException {
return new R(snapshot);
}
@Override
public void addChangeListener(ChangeListener changeListener) {
}
@Override
public void removeChangeListener(ChangeListener changeListener) {
}
public static class R extends Result {
private final List<CharSequence> embs;
public R(@NonNull final Snapshot snapshot) {
super(snapshot);
embs = new ArrayList<CharSequence>();
int embStart = -1;
final CharSequence text = snapshot.getText();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c == '{') {
embStart = i+1;
} else if (c == '}' && embStart >= 0) {
CharSequence emb = text.subSequence(embStart, i);
embs.add(emb);
}
}
}
@Override
protected void invalidate() {
}
public List<CharSequence> getEmbeddings() {
return embs;
}
}
public static class Factory extends ParserFactory {
@Override
public Parser createParser(Collection<Snapshot> snapshots) {
return new FooParser();
}
}
}
public static final class EmbParser extends Parser {
private Snapshot snapshot;
@Override
public void parse(Snapshot snapshot, Task task, SourceModificationEvent event) throws ParseException {
this.snapshot = snapshot;
}
@Override
public Result getResult(Task task) throws ParseException {
return new Result(snapshot) {
@Override
protected void invalidate() {
}
};
}
@Override
public void addChangeListener(ChangeListener changeListener) {
}
@Override
public void removeChangeListener(ChangeListener changeListener) {
}
public static class Factory extends ParserFactory {
@Override
public Parser createParser(Collection<Snapshot> snapshots) {
return new EmbParser();
}
}
}
public static final class EmbEmbeddingProvider extends EmbeddingProvider {
@Override
public List<Embedding> getEmbeddings(final Snapshot snapshot) {
try {
final FileObject file = snapshot.getSource().getFileObject();
final ClassPath scp = ClassPath.getClassPath(file, FooPathRecognizer.FOO_SOURCES);
final FileObject root = scp.findOwnerRoot(file);
QuerySupport qs = QuerySupport.forRoots(EmbIndexer.EMB_INDEXER_NAME, EmbIndexer.EMB_INDEXER_VERSION, root);
Collection<? extends IndexResult> res = qs.query(
"key", //NOI18N
"", //NOI18N
QuerySupport.Kind.PREFIX,
"key"); //NOI18N
StringBuilder oldState = new StringBuilder("OLD STATE: "); //NOI18N
for (IndexResult r : res) {
oldState.append(r.getValue("key")); //NOI18N
oldState.append(' '); //NOI18N
}
System.out.println(oldState);
final List<Embedding> result = new ArrayList<Embedding>();
ParserManager.parse(
Collections.singleton(snapshot.getSource()),
new UserTask() {
@Override
public void run(ResultIterator resultIterator) throws Exception {
final Parser.Result res = resultIterator.getParserResult();
for (CharSequence cs : ((FooParser.R)res).getEmbeddings()) {
result.add(snapshot.create(cs, EmbeddedPathRecognizer.EMB_MIME));
}
}
});
return result;
} catch (ParseException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public int getPriority() {
return 1;
}
@Override
public void cancel() {
}
public static class Factory extends TaskFactory {
@Override
public Collection<? extends SchedulerTask> create(Snapshot snapshot) {
return Collections.singleton(new EmbEmbeddingProvider());
}
}
}
public static final class FooIndexer extends EmbeddingIndexer {
@Override
protected void index(Indexable indexable, Parser.Result parserResult, Context context) {
System.out.println("FOO: " + parserResult.getSnapshot().getText());
}
public static final class Factory extends EmbeddingIndexerFactory {
public static final String FOO_INDEXER_NAME = "Foo-Indexer"; //NOI18N
public static final int FOO_INDEXER_VERSION = 1;
@Override
public EmbeddingIndexer createIndexer(Indexable indexable, Snapshot snapshot) {
return new FooIndexer();
}
@Override
public void filesDeleted(Iterable<? extends Indexable> deleted, Context context) {
}
@Override
public void filesDirty(Iterable<? extends Indexable> dirty, Context context) {
try {
final IndexingSupport is = IndexingSupport.getInstance(context);
for (Indexable i : dirty) {
is.markDirtyDocuments(i);
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
public String getIndexerName() {
return FOO_INDEXER_NAME;
}
@Override
public int getIndexVersion() {
return FOO_INDEXER_VERSION;
}
}
}
public static final class EmbIndexer extends EmbeddingIndexer {
public static final String EMB_INDEXER_NAME = "Emb-Indexer"; //NOI18N
public static final int EMB_INDEXER_VERSION = 1;
private final Factory f;
private EmbIndexer (@NonNull final Factory f) {
this.f = f;
}
@Override
protected void index(Indexable indexable, Parser.Result parserResult, Context context) {
try {
System.out.println("EMB: " + parserResult.getSnapshot().getText());
IndexingSupport is = IndexingSupport.getInstance(context);
if (!indexable.equals(f.lastIndexable)) {
is.removeDocuments(indexable);
f.lastIndexable = indexable;
}
final IndexDocument doc = is.createDocument(indexable);
doc.addPair(
"key", //NOI18N
parserResult.getSnapshot().getText().toString(),
true,
true);
is.addDocument(doc);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
public static final class Factory extends EmbeddingIndexerFactory {
private Indexable lastIndexable;
@Override
public EmbeddingIndexer createIndexer(Indexable indexable, Snapshot snapshot) {
return new EmbIndexer(this);
}
@Override
public void filesDeleted(Iterable<? extends Indexable> deleted, Context context) {
}
@Override
public void filesDirty(Iterable<? extends Indexable> dirty, Context context) {
try {
final IndexingSupport is = IndexingSupport.getInstance(context);
for (Indexable i : dirty) {
is.markDirtyDocuments(i);
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
public String getIndexerName() {
return EMB_INDEXER_NAME;
}
@Override
public int getIndexVersion() {
return EMB_INDEXER_VERSION;
}
@Override
public boolean scanStarted(Context context) {
lastIndexable = null;
return super.scanStarted(context);
}
}
}
public static final class ClassPathProviderImpl implements ClassPathProvider {
private volatile Pair<FileObject[],ClassPath> roots2cp;
@Override
public ClassPath findClassPath(FileObject file, String type) {
if (FooPathRecognizer.FOO_SOURCES.equals(type)) {
final Pair<FileObject[],ClassPath> _roots2cp = roots2cp;
if (_roots2cp != null) {
for (FileObject root : _roots2cp.first()) {
if (root.equals(file) || FileUtil.isParentOf(root, file)) {
return _roots2cp.second();
}
}
}
}
return null;
}
}
}