This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 229059
Collapse All | Expand All

(-)a/parsing.api/apichanges.xml (+15 lines)
Lines 110-115 Link Here
110
<!-- ACTUAL CHANGES BEGIN HERE: -->
110
<!-- ACTUAL CHANGES BEGIN HERE: -->
111
111
112
  <changes>
112
  <changes>
113
  <change id="QuerySupport.Query">
114
      <api name="ParsingAPI"/>
115
      <summary>Extended the <code>QuerySupport</code> to allow composite queries.</summary>
116
      <version major="1" minor="64"/>
117
      <date day="2" month="5" year="2013"/>
118
      <author login="tzezula"/>
119
      <compatibility source="compatible" binary="compatible" semantic="compatible" deletion="no" addition="yes" modification="no"/>
120
      <description>
121
          <p>
122
              Extended the <code>QuerySupport</code> to allow composite queries with bool operators.
123
          </p>
124
      </description>
125
      <class package="org.netbeans.modules.parsing.spi.indexing.support" name="QuerySupport"/>
126
      <issue number="170915"/>
127
  </change>
113
  <change id="QuerySupport.findDependentRoots">
128
  <change id="QuerySupport.findDependentRoots">
114
      <api name="ParsingAPI"/>
129
      <api name="ParsingAPI"/>
115
      <summary>Added <code>QuerySupport.findDependentRoots</code> to find out source roots depending on given source root.</summary>
130
      <summary>Added <code>QuerySupport.findDependentRoots</code> to find out source roots depending on given source root.</summary>
(-)a/parsing.api/nbproject/project.properties (-1 / +1 lines)
Lines 3-9 Link Here
3
javac.source=1.6
3
javac.source=1.6
4
javadoc.apichanges=${basedir}/apichanges.xml
4
javadoc.apichanges=${basedir}/apichanges.xml
5
javadoc.arch=${basedir}/arch.xml
5
javadoc.arch=${basedir}/arch.xml
6
spec.version.base=1.65.0
6
spec.version.base=1.66.0
7
7
8
test.config.stableBTD.includes=**/*Test.class
8
test.config.stableBTD.includes=**/*Test.class
9
test.config.stableBTD.excludes=\
9
test.config.stableBTD.excludes=\
(-)a/parsing.api/nbproject/project.xml (-1 / +1 lines)
Lines 110-116 Link Here
110
                    <compile-dependency/>
110
                    <compile-dependency/>
111
                    <run-dependency>
111
                    <run-dependency>
112
                        <release-version>2</release-version>
112
                        <release-version>2</release-version>
113
                        <specification-version>2.22</specification-version>
113
                        <specification-version>2.24</specification-version>
114
                    </run-dependency>
114
                    </run-dependency>
115
                </dependency>
115
                </dependency>
116
                <dependency>
116
                <dependency>
(-)a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/lucene/DocumentBasedIndexManager.java (-13 / +13 lines)
Lines 53-59 Link Here
53
import org.netbeans.modules.parsing.impl.indexing.ClusteredIndexables;
53
import org.netbeans.modules.parsing.impl.indexing.ClusteredIndexables;
54
import org.netbeans.modules.parsing.impl.indexing.Pair;
54
import org.netbeans.modules.parsing.impl.indexing.Pair;
55
import org.netbeans.modules.parsing.impl.indexing.PathRegistry;
55
import org.netbeans.modules.parsing.impl.indexing.PathRegistry;
56
import org.netbeans.modules.parsing.lucene.support.DocumentIndex;
56
import org.netbeans.modules.parsing.lucene.support.DocumentIndex2;
57
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
57
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
58
import org.netbeans.modules.parsing.lucene.support.IndexManager;
58
import org.netbeans.modules.parsing.lucene.support.IndexManager;
59
import org.openide.util.Exceptions;
59
import org.openide.util.Exceptions;
Lines 72-79 Link Here
72
    @org.netbeans.api.annotations.common.SuppressWarnings(
72
    @org.netbeans.api.annotations.common.SuppressWarnings(
73
    value="DMI_COLLECTION_OF_URLS",
73
    value="DMI_COLLECTION_OF_URLS",
74
    justification="URLs have never host part")
74
    justification="URLs have never host part")
75
    private final Map<URL, Pair<DocumentIndex.Transactional, DocumentIndexCache>> indexes =
75
    private final Map<URL, Pair<DocumentIndex2.Transactional, DocumentIndexCache>> indexes =
76
            new HashMap<URL, Pair<DocumentIndex.Transactional, DocumentIndexCache>> ();
76
            new HashMap<URL, Pair<DocumentIndex2.Transactional, DocumentIndexCache>> ();
77
    //@GuardedBy("this")
77
    //@GuardedBy("this")
78
    private boolean closed;
78
    private boolean closed;
79
79
Lines 98-110 Link Here
98
   @org.netbeans.api.annotations.common.SuppressWarnings(
98
   @org.netbeans.api.annotations.common.SuppressWarnings(
99
    value="DMI_COLLECTION_OF_URLS",
99
    value="DMI_COLLECTION_OF_URLS",
100
    justification="URLs have never host part")
100
    justification="URLs have never host part")
101
    public synchronized DocumentIndex.Transactional getIndex (final URL root, final Mode mode) throws IOException {
101
    public synchronized DocumentIndex2.Transactional getIndex (final URL root, final Mode mode) throws IOException {
102
        assert root != null;
102
        assert root != null;
103
        assert PathRegistry.noHostPart(root) : root;
103
        assert PathRegistry.noHostPart(root) : root;
104
        if (closed) {
104
        if (closed) {
105
            return null;
105
            return null;
106
        }
106
        }
107
        Pair<DocumentIndex.Transactional, DocumentIndexCache> li = indexes.get(root);
107
        Pair<DocumentIndex2.Transactional, DocumentIndexCache> li = indexes.get(root);
108
        if (li == null) {
108
        if (li == null) {
109
            try {
109
            try {
110
                switch (mode) {
110
                switch (mode) {
Lines 113-120 Link Here
113
                        final File file = Utilities.toFile(root.toURI());
113
                        final File file = Utilities.toFile(root.toURI());
114
                        file.mkdir();
114
                        file.mkdir();
115
                        final DocumentIndexCache cache = ClusteredIndexables.createDocumentIndexCache();
115
                        final DocumentIndexCache cache = ClusteredIndexables.createDocumentIndexCache();
116
                        final DocumentIndex.Transactional index = IndexManager.createTransactionalDocumentIndex(file, cache);
116
                        final DocumentIndex2.Transactional index = (DocumentIndex2.Transactional) IndexManager.createTransactionalDocumentIndex(file, cache);
117
                        li = Pair.<DocumentIndex.Transactional, DocumentIndexCache>of(index, cache);
117
                        li = Pair.<DocumentIndex2.Transactional, DocumentIndexCache>of(index, cache);
118
118
119
                        indexes.put(root,li);
119
                        indexes.put(root,li);
120
                        break;
120
                        break;
Lines 125-132 Link Here
125
                        String[] children;
125
                        String[] children;
126
                        if (file.isDirectory() && (children=file.list())!= null && children.length > 0) {
126
                        if (file.isDirectory() && (children=file.list())!= null && children.length > 0) {
127
                            final DocumentIndexCache cache = ClusteredIndexables.createDocumentIndexCache();
127
                            final DocumentIndexCache cache = ClusteredIndexables.createDocumentIndexCache();
128
                            final DocumentIndex.Transactional index = IndexManager.createTransactionalDocumentIndex(file, cache);
128
                            final DocumentIndex2.Transactional index = (DocumentIndex2.Transactional) IndexManager.createTransactionalDocumentIndex(file, cache);
129
                            li = Pair.<DocumentIndex.Transactional, DocumentIndexCache>of(index, cache);
129
                            li = Pair.<DocumentIndex2.Transactional, DocumentIndexCache>of(index, cache);
130
                            indexes.put(root,li);
130
                            indexes.put(root,li);
131
                        }
131
                        }
132
                        break;
132
                        break;
Lines 141-154 Link Here
141
141
142
   @CheckForNull
142
   @CheckForNull
143
   public synchronized DocumentIndexCache getCache(@NonNull final URL root) {
143
   public synchronized DocumentIndexCache getCache(@NonNull final URL root) {
144
       final Pair<DocumentIndex.Transactional, DocumentIndexCache> entry = indexes.get(root);
144
       final Pair<DocumentIndex2.Transactional, DocumentIndexCache> entry = indexes.get(root);
145
       return entry == null ? null : entry.second;
145
       return entry == null ? null : entry.second;
146
   }
146
   }
147
147
148
   @CheckForNull
148
   @CheckForNull
149
   public synchronized DocumentIndex.Transactional getIndex(@NonNull final DocumentIndexCache cache) {
149
   public synchronized DocumentIndex2.Transactional getIndex(@NonNull final DocumentIndexCache cache) {
150
       Parameters.notNull("cache", cache);  //NOI18N
150
       Parameters.notNull("cache", cache);  //NOI18N
151
       for (Pair<DocumentIndex.Transactional,DocumentIndexCache> e : indexes.values()) {
151
       for (Pair<DocumentIndex2.Transactional,DocumentIndexCache> e : indexes.values()) {
152
           if (cache.equals(e.second)) {
152
           if (cache.equals(e.second)) {
153
               return e.first;
153
               return e.first;
154
           }
154
           }
Lines 161-167 Link Here
161
           return;
161
           return;
162
       }
162
       }
163
       closed = true;
163
       closed = true;
164
       for (Pair<DocumentIndex.Transactional, DocumentIndexCache> index : indexes.values()) {
164
       for (Pair<DocumentIndex2.Transactional, DocumentIndexCache> index : indexes.values()) {
165
           try {
165
           try {
166
            index.first.close();
166
            index.first.close();
167
           } catch (IOException ioe) {
167
           } catch (IOException ioe) {
(-)a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/lucene/LayeredDocumentIndex.java (-33 / +90 lines)
Lines 49-77 Link Here
49
import java.util.Iterator;
49
import java.util.Iterator;
50
import java.util.Set;
50
import java.util.Set;
51
import org.apache.lucene.analysis.KeywordAnalyzer;
51
import org.apache.lucene.analysis.KeywordAnalyzer;
52
import org.apache.lucene.search.Query;
53
import org.netbeans.api.annotations.common.CheckForNull;
52
import org.netbeans.api.annotations.common.NonNull;
54
import org.netbeans.api.annotations.common.NonNull;
55
import org.netbeans.api.annotations.common.NullAllowed;
53
import org.netbeans.modules.parsing.impl.indexing.Pair;
56
import org.netbeans.modules.parsing.impl.indexing.Pair;
54
import org.netbeans.modules.parsing.lucene.support.DocumentIndex;
57
import org.netbeans.modules.parsing.lucene.support.DocumentIndex2;
55
import org.netbeans.modules.parsing.lucene.support.Index.Status;
58
import org.netbeans.modules.parsing.lucene.support.Index.Status;
56
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
59
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
57
import org.netbeans.modules.parsing.lucene.support.IndexManager;
60
import org.netbeans.modules.parsing.lucene.support.IndexManager;
58
import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
61
import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
59
import org.openide.util.Exceptions;
62
import org.openide.util.Exceptions;
60
import static org.netbeans.modules.parsing.impl.indexing.TransientUpdateSupport.isTransientUpdate;
63
import static org.netbeans.modules.parsing.impl.indexing.TransientUpdateSupport.isTransientUpdate;
64
import org.netbeans.modules.parsing.lucene.support.Convertor;
65
import org.netbeans.modules.parsing.lucene.support.Convertors;
66
import org.netbeans.modules.parsing.lucene.support.Queries;
61
/**
67
/**
62
 *
68
 *
63
 * @author Tomas Zezula
69
 * @author Tomas Zezula
64
 */
70
 */
65
public final class LayeredDocumentIndex implements DocumentIndex.Transactional {
71
public final class LayeredDocumentIndex implements DocumentIndex2.Transactional {
66
    
72
    
67
    private final DocumentIndex.Transactional base;
73
    private final DocumentIndex2.Transactional base;
68
    
74
    
69
    private final Set<String> filter = new HashSet<String>();
75
    private final Set<String> filter = new HashSet<String>();
70
    //@GuardedBy("this")
76
    //@GuardedBy("this")
71
    private DocumentIndex overlay;
77
    private DocumentIndex2 overlay;
72
    
78
    
73
    
79
    
74
    LayeredDocumentIndex(@NonNull final DocumentIndex.Transactional base) {
80
    LayeredDocumentIndex(@NonNull final DocumentIndex2.Transactional base) {
75
        assert base != null;
81
        assert base != null;
76
        this.base = base;
82
        this.base = base;
77
    }
83
    }
Lines 117-123 Link Here
117
    @Override
123
    @Override
118
    public void store(boolean optimize) throws IOException {
124
    public void store(boolean optimize) throws IOException {
119
        if (isTransientUpdate()) {
125
        if (isTransientUpdate()) {
120
            final Pair<DocumentIndex,Set<String>> ovl = getOverlayIfExists();
126
            final Pair<DocumentIndex2,Set<String>> ovl = getOverlayIfExists();
121
            if (ovl.first != null) {
127
            if (ovl.first != null) {
122
                ovl.first.store(false);
128
                ovl.first.store(false);
123
            }
129
            }
Lines 165-195 Link Here
165
171
166
    @Override
172
    @Override
167
    public Collection<? extends IndexDocument> query(String fieldName, String value, QueryKind kind, String... fieldsToLoad) throws IOException, InterruptedException {
173
    public Collection<? extends IndexDocument> query(String fieldName, String value, QueryKind kind, String... fieldsToLoad) throws IOException, InterruptedException {
168
        final Collection<? extends IndexDocument> br = base.query(fieldName, value, kind, fieldsToLoad);
174
        return query(Queries.createQuery(fieldName, fieldName, value, kind), Convertors.<IndexDocument>identity(), fieldsToLoad);
169
        final Pair<DocumentIndex,Set<String>> ovl = getOverlayIfExists();
170
        if (ovl.first == null) {
171
            return ovl.second == null ? br : filter(br,ovl.second);
172
        } else {
173
            return new ProxyCollection<IndexDocument>(
174
                ovl.second == null ? br : filter(br,ovl.second),
175
                ovl.first.query(fieldName, value, kind, fieldsToLoad));
176
        }
177
    }
175
    }
178
176
179
    @Override
177
    @Override
180
    public Collection<? extends IndexDocument> findByPrimaryKey(String primaryKeyValue, QueryKind kind, String... fieldsToLoad) throws IOException, InterruptedException {
178
    public Collection<? extends IndexDocument> findByPrimaryKey(String primaryKeyValue, QueryKind kind, String... fieldsToLoad) throws IOException, InterruptedException {
181
        final Collection<? extends IndexDocument> br = base.findByPrimaryKey(primaryKeyValue, kind, fieldsToLoad);
179
        final Collection<? extends IndexDocument> br = base.findByPrimaryKey(primaryKeyValue, kind, fieldsToLoad);
182
        final Pair<DocumentIndex,Set<String>> ovl = getOverlayIfExists();
180
        final Pair<DocumentIndex2,Set<String>> ovl = getOverlayIfExists();
183
        if (ovl.first == null) {
181
        if (ovl.first == null) {
184
            return ovl.second == null ? br : filter(br, ovl.second);
182
            return ovl.second == null ? br : Filter.filter(br, ovl.second);
185
        } else {
183
        } else {
186
            return new ProxyCollection<IndexDocument>(
184
            return new ProxyCollection<IndexDocument>(
187
                ovl.second == null ? br : filter(br,ovl.second),
185
                ovl.second == null ? br : Filter.filter(br,ovl.second),
188
                ovl.first.findByPrimaryKey(primaryKeyValue, kind, fieldsToLoad));
186
                ovl.first.findByPrimaryKey(primaryKeyValue, kind, fieldsToLoad));
189
        }
187
        }
190
    }
188
    }
191
189
192
    @Override
190
    @Override
191
    @NonNull
192
    public <T> Collection<? extends T> query(
193
            @NonNull final Query query,
194
            @NonNull final Convertor<? super IndexDocument, ? extends T> convertor,
195
            @NullAllowed final String... fieldsToLoad) throws IOException, InterruptedException {
196
        final Pair<DocumentIndex2,Set<String>> ovl = getOverlayIfExists();
197
        Convertor<? super IndexDocument, ? extends T> filterConvertor;
198
        if (ovl.second == null) {
199
            filterConvertor = convertor;
200
        } else {
201
            filterConvertor = Convertors.compose(
202
                    new Filter(ovl.second),
203
                    convertor);
204
        }
205
        final Collection<? extends T> br = base.query(
206
                query,
207
                filterConvertor,
208
                fieldsToLoad);
209
        
210
        if (ovl.first == null) {
211
            return br;
212
        } else {
213
            return new ProxyCollection<T>(
214
                br,
215
                ovl.first.query(query, convertor, fieldsToLoad));
216
        }
217
    }
218
219
220
221
    @Override
193
    public void markKeyDirty(String primaryKey) {
222
    public void markKeyDirty(String primaryKey) {
194
        addToFilter(primaryKey);
223
        addToFilter(primaryKey);
195
        base.markKeyDirty(primaryKey);
224
        base.markKeyDirty(primaryKey);
Lines 220-236 Link Here
220
    }
249
    }
221
    
250
    
222
    @NonNull
251
    @NonNull
223
    private synchronized DocumentIndex getOverlay() throws IOException {
252
    private synchronized DocumentIndex2 getOverlay() throws IOException {
224
        if (overlay == null) {
253
        if (overlay == null) {
225
            overlay = IndexManager.createDocumentIndex(IndexManager.createMemoryIndex(new KeywordAnalyzer()));
254
            overlay = (DocumentIndex2) IndexManager.createDocumentIndex(IndexManager.createMemoryIndex(new KeywordAnalyzer()));
226
        }
255
        }
227
        return overlay;
256
        return overlay;
228
    }
257
    }
229
    
258
    
230
    @NonNull
259
    @NonNull
231
    private synchronized Pair<DocumentIndex,Set<String>> getOverlayIfExists() throws IOException {
260
    private synchronized Pair<DocumentIndex2,Set<String>> getOverlayIfExists() throws IOException {
232
        final Set<String> f = filter.isEmpty() ? null : new HashSet<String>(filter);
261
        final Set<String> f = filter.isEmpty() ? null : new HashSet<String>(filter);
233
        return Pair.<DocumentIndex,Set<String>>of(overlay,f);
262
        return Pair.<DocumentIndex2,Set<String>>of(overlay,f);
234
    }
263
    }
235
    
264
    
236
    private synchronized void addToFilter(@NonNull final String primaryKey) {
265
    private synchronized void addToFilter(@NonNull final String primaryKey) {
Lines 249-267 Link Here
249
            }
278
            }
250
        }
279
        }
251
    }
280
    }
252
    
281
253
    @NonNull
282
    private static final class Filter implements Convertor<IndexDocument, IndexDocument> {
254
    private static Collection<? extends IndexDocument> filter (
283
255
        @NonNull final Collection<? extends IndexDocument> base,
284
        private final Set<String> filter;
256
        @NonNull final Set<String> filter) {
285
257
        assert !filter.isEmpty();
286
        Filter(@NonNull final Set<String> filter) {
258
        final Collection<IndexDocument> res = new ArrayList<IndexDocument>(base.size());
287
            assert filter != null;
259
        for (IndexDocument doc : base) {
288
            assert !filter.isEmpty();
260
            if (!filter.contains(doc.getPrimaryKey())) {
289
            this.filter = filter;
261
                res.add(doc);
290
        }
291
292
        @Override
293
        @CheckForNull
294
        public IndexDocument convert(@NullAllowed final IndexDocument p) {
295
            return filtered(p, filter) ?
296
                null :
297
                p;
298
        }
299
300
        @NonNull
301
        static Collection<? extends IndexDocument> filter (
302
            @NonNull final Collection<? extends IndexDocument> base,
303
            @NonNull final Set<String> filter) {
304
            assert !filter.isEmpty();
305
            final Collection<IndexDocument> res = new ArrayList<IndexDocument>(base.size());
306
            for (IndexDocument doc : base) {
307
                if (!filtered(doc, filter)) {
308
                    res.add(doc);
309
                }
262
            }
310
            }
311
            return res;
263
        }
312
        }
264
        return res;
313
314
        private static boolean filtered(
315
            @NullAllowed final IndexDocument doc,
316
            @NonNull final Set<? extends String> filter) {
317
            return doc == null ?
318
                true :
319
                filter.contains(doc.getPrimaryKey());
320
        }
321
265
    }
322
    }
266
    
323
    
267
    private static class ProxyCollection<E> extends AbstractCollection<E> {
324
    private static class ProxyCollection<E> extends AbstractCollection<E> {
(-)a/parsing.api/src/org/netbeans/modules/parsing/impl/indexing/lucene/LuceneIndexFactory.java (-2 / +2 lines)
Lines 52-58 Link Here
52
import org.netbeans.modules.parsing.impl.indexing.IndexFactoryImpl;
52
import org.netbeans.modules.parsing.impl.indexing.IndexFactoryImpl;
53
import org.netbeans.modules.parsing.impl.indexing.TransientUpdateSupport;
53
import org.netbeans.modules.parsing.impl.indexing.TransientUpdateSupport;
54
import org.netbeans.modules.parsing.impl.indexing.Util;
54
import org.netbeans.modules.parsing.impl.indexing.Util;
55
import org.netbeans.modules.parsing.lucene.support.DocumentIndex;
55
import org.netbeans.modules.parsing.lucene.support.DocumentIndex2;
56
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
56
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
57
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
57
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
58
import org.netbeans.modules.parsing.lucene.support.IndexManager;
58
import org.netbeans.modules.parsing.lucene.support.IndexManager;
Lines 130-136 Link Here
130
            }
130
            }
131
            LayeredDocumentIndex res = indexes.get(luceneIndexFolder);
131
            LayeredDocumentIndex res = indexes.get(luceneIndexFolder);
132
            if (res == null) {
132
            if (res == null) {
133
                final DocumentIndex.Transactional base = DocumentBasedIndexManager.getDefault().getIndex(
133
                final DocumentIndex2.Transactional base = DocumentBasedIndexManager.getDefault().getIndex(
134
                        luceneIndexFolder,
134
                        luceneIndexFolder,
135
                        mode);
135
                        mode);
136
                if (base != null) {
136
                if (base != null) {
(-)a/parsing.api/src/org/netbeans/modules/parsing/spi/indexing/support/QuerySupport.java (-73 / +222 lines)
Lines 47-52 Link Here
47
import java.lang.ref.SoftReference;
47
import java.lang.ref.SoftReference;
48
import java.net.MalformedURLException;
48
import java.net.MalformedURLException;
49
import java.net.URL;
49
import java.net.URL;
50
import java.util.ArrayDeque;
50
import java.util.ArrayList;
51
import java.util.ArrayList;
51
import java.util.Arrays;
52
import java.util.Arrays;
52
import java.util.Collection;
53
import java.util.Collection;
Lines 56-67 Link Here
56
import java.util.LinkedList;
57
import java.util.LinkedList;
57
import java.util.List;
58
import java.util.List;
58
import java.util.Map;
59
import java.util.Map;
60
import java.util.Queue;
59
import java.util.Set;
61
import java.util.Set;
60
import java.util.concurrent.Callable;
62
import java.util.concurrent.Callable;
61
import java.util.logging.Level;
63
import java.util.logging.Level;
62
import java.util.logging.Logger;
64
import java.util.logging.Logger;
65
import org.apache.lucene.search.BooleanClause;
63
import org.netbeans.api.annotations.common.CheckForNull;
66
import org.netbeans.api.annotations.common.CheckForNull;
64
import org.netbeans.api.annotations.common.NonNull;
67
import org.netbeans.api.annotations.common.NonNull;
68
import org.netbeans.api.annotations.common.NullAllowed;
65
import org.netbeans.api.java.classpath.ClassPath;
69
import org.netbeans.api.java.classpath.ClassPath;
66
import org.netbeans.api.java.classpath.GlobalPathRegistry;
70
import org.netbeans.api.java.classpath.GlobalPathRegistry;
67
import org.netbeans.api.java.queries.SourceForBinaryQuery;
71
import org.netbeans.api.java.queries.SourceForBinaryQuery;
Lines 83-90 Link Here
83
import org.netbeans.modules.parsing.impl.indexing.friendapi.IndexingController;
87
import org.netbeans.modules.parsing.impl.indexing.friendapi.IndexingController;
84
import org.netbeans.modules.parsing.impl.indexing.lucene.LayeredDocumentIndex;
88
import org.netbeans.modules.parsing.impl.indexing.lucene.LayeredDocumentIndex;
85
import org.netbeans.modules.parsing.impl.indexing.lucene.LuceneIndexFactory;
89
import org.netbeans.modules.parsing.impl.indexing.lucene.LuceneIndexFactory;
86
import org.netbeans.modules.parsing.lucene.support.DocumentIndex;
90
import org.netbeans.modules.parsing.lucene.support.Convertor;
91
import org.netbeans.modules.parsing.lucene.support.DocumentIndex2;
87
import org.netbeans.modules.parsing.lucene.support.Index;
92
import org.netbeans.modules.parsing.lucene.support.Index;
93
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
88
import org.netbeans.modules.parsing.lucene.support.Queries;
94
import org.netbeans.modules.parsing.lucene.support.Queries;
89
import org.openide.filesystems.FileObject;
95
import org.openide.filesystems.FileObject;
90
import org.openide.filesystems.FileStateInvalidException;
96
import org.openide.filesystems.FileStateInvalidException;
Lines 319-397 Link Here
319
        Parameters.notNull("fieldName", fieldName); //NOI18N
325
        Parameters.notNull("fieldName", fieldName); //NOI18N
320
        Parameters.notNull("fieldValue", fieldValue); //NOI18N
326
        Parameters.notNull("fieldValue", fieldValue); //NOI18N
321
        Parameters.notNull("kind", kind); //NOI18N
327
        Parameters.notNull("kind", kind); //NOI18N
322
        try {
328
        return getQueryFactory().field(fieldName, fieldValue, kind).execute(fieldsToLoad);
323
            return Utilities.runPriorityIO(new Callable<Collection<? extends IndexResult>>() {
329
    }
324
330
325
                @Override
331
326
                public Collection<? extends IndexResult> call() throws Exception {
332
    /**
327
                    Iterable<? extends Pair<URL, LayeredDocumentIndex>> indices = indexerQuery.getIndices(roots);
333
     * Returns the factory for creating composite queries.
328
                    // check if there are stale indices
334
     * @return the {@link QuerySupport.Query.Factory}
329
                    for (Pair<URL, LayeredDocumentIndex> pair : indices) {
335
     * @since 1.66
330
                        final LayeredDocumentIndex index = pair.second;
336
     */
331
                        final Collection<? extends String> staleFiles = index.getDirtyKeys();
337
    @NonNull
332
                        final boolean scanningThread = RunWhenScanFinishedSupport.isScanningThread();
338
    public Query.Factory getQueryFactory() {
333
                        LOG.log(
339
        return new Query.Factory(this);
334
                            Level.FINE,
335
                            "Index: {0}, staleFiles: {1}, scanning thread: {2}",  //NOI18N
336
                            new Object[]{
337
                                index,
338
                                staleFiles,
339
                                scanningThread
340
                            });
341
                        if (!staleFiles.isEmpty() && !scanningThread) {
342
                            final URL root = pair.first;
343
                            LinkedList<URL> list = new LinkedList<URL>();
344
                            for (String staleFile : staleFiles) {
345
                                try {
346
                                    list.add(Util.resolveUrl(root, staleFile, false));
347
                                } catch (MalformedURLException ex) {
348
                                    LOG.log(Level.WARNING, null, ex);
349
                                }
350
                            }
351
                            TransientUpdateSupport.setTransientUpdate(true);
352
                            try {
353
                                RepositoryUpdater.getDefault().enforcedFileListUpdate(root,list);
354
                            } finally {
355
                                TransientUpdateSupport.setTransientUpdate(false);
356
                            }
357
                        }
358
                    }
359
                    final List<IndexResult> result = new LinkedList<IndexResult>();
360
                    for (Pair<URL, LayeredDocumentIndex> pair : indices) {
361
                        final DocumentIndex index = pair.second;
362
                        final URL root = pair.first;
363
                        final Collection<? extends org.netbeans.modules.parsing.lucene.support.IndexDocument> pr = index.query(
364
                                fieldName,
365
                                fieldValue,
366
                                translateQueryKind(kind),
367
                                fieldsToLoad);
368
                        if (LOG.isLoggable(Level.FINE)) {
369
                            LOG.fine("query(\"" + fieldName + "\", \"" + fieldValue + "\", " + kind + ", " + printFiledToLoad(fieldsToLoad) + ") invoked at " + getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + "[indexer=" + indexerQuery.getIndexerId() + "]:"); //NOI18N
370
                            for (org.netbeans.modules.parsing.lucene.support.IndexDocument idi : pr) {
371
                                LOG.fine(" " + idi); //NOI18N
372
                            }
373
                            LOG.fine("----"); //NOI18N
374
                        }
375
                        for (org.netbeans.modules.parsing.lucene.support.IndexDocument di : pr) {
376
                            result.add(new IndexResult(di, root));
377
                        }
378
                    }
379
                    return result;
380
                }
381
            });
382
        } catch (Index.IndexClosedException ice) {
383
            if (Installer.isClosed()) {
384
                return Collections.<IndexResult>emptySet();
385
            } else {
386
                throw ice;
387
            }
388
        } catch (IOException ioe) {
389
            throw ioe;
390
        } catch (RuntimeException re) {
391
            throw re;
392
        } catch (Exception ex) {
393
            throw new IOException(ex);
394
        }
395
    }
340
    }
396
341
397
    /**
342
    /**
Lines 433-438 Link Here
433
        CASE_INSENSITIVE_CAMEL_CASE;
378
        CASE_INSENSITIVE_CAMEL_CASE;
434
    }
379
    }
435
380
381
    /**
382
     * An index query.
383
     * @since 1.66
384
     */
385
    public static final class Query {
386
387
        private final QuerySupport qs;
388
        private final org.apache.lucene.search.Query queryImpl;
389
390
        private Query(
391
            @NonNull final QuerySupport qs,
392
            @NonNull final org.apache.lucene.search.Query queryImpl) {
393
            assert qs != null;
394
            assert queryImpl != null;
395
            this.qs = qs;
396
            this.queryImpl = queryImpl;
397
        }
398
399
        /**
400
         * Factory for an index queries.
401
         */
402
        public static final class Factory {
403
404
            private final QuerySupport qs;
405
406
            private Factory(@NonNull final QuerySupport qs) {
407
                assert qs != null;
408
                this.qs = qs;
409
            }
410
411
            /**
412
             * Creates a query for required field value.
413
             * @param fieldName the name of the tested field
414
             * @param fieldValue the required value of the tested field
415
             * @param kind the kind of the query
416
             * @return the newly created query
417
             */
418
            @NonNull
419
            public Query field(
420
                @NonNull final String fieldName,
421
                @NonNull final String fieldValue,
422
                @NonNull final Kind kind) {
423
                Parameters.notNull("fieldName", fieldName); //NOI18N
424
                Parameters.notNull("fieldValue", fieldValue);   //NOI18N
425
                Parameters.notNull("kind", kind);   //NOI18N
426
                return new Query(
427
                    qs,
428
                    Queries.createQuery(
429
                        fieldName,
430
                        fieldName,
431
                        fieldValue,
432
                        translateQueryKind(kind)));
433
            }
434
435
            /**
436
             * Creates a boolean AND query.
437
             * @param queries the queries to compose into the AND query
438
             * @return the newly created AND query
439
             */
440
            @NonNull
441
            public Query and(@NonNull final Query...queries) {
442
                Parameters.notNull("queries", queries);     //NOI18N
443
                final org.apache.lucene.search.BooleanQuery bq = new org.apache.lucene.search.BooleanQuery();
444
                for (Query q : queries) {
445
                    bq.add(new BooleanClause(q.queryImpl, org.apache.lucene.search.BooleanClause.Occur.MUST));
446
                }
447
                return new Query(
448
                    qs,
449
                    bq);
450
            }
451
452
            /**
453
             * Creates a boolean OR query.
454
             * @param queries the queries to compose into the OR query
455
             * @return the newly created OR query
456
             */
457
            @NonNull
458
            public Query or(@NonNull final Query...queries) {
459
                Parameters.notNull("queries", queries);     //NOI18N
460
                final org.apache.lucene.search.BooleanQuery bq = new org.apache.lucene.search.BooleanQuery();
461
                for (Query q : queries) {
462
                    bq.add(new BooleanClause(q.queryImpl, org.apache.lucene.search.BooleanClause.Occur.SHOULD));
463
                }
464
                return new Query(
465
                    qs,
466
                    bq);
467
            }
468
        }
469
470
        /**
471
         * Executes the query.
472
         * @param fieldsToLoad the filter for fields to be loaded into the {@link IndexResult}s
473
         * @return the {@link Collection} of {@link IndexResult} matching the {@link QuerySupport.Query}
474
         * @throws IOException in case of IO error.
475
         */
476
        @NonNull
477
        public Collection<? extends IndexResult> execute(@NullAllowed final String... fieldsToLoad) throws IOException {
478
            try {
479
            return Utilities.runPriorityIO(new Callable<Collection<? extends IndexResult>>() {
480
                @Override
481
                public Collection<? extends IndexResult> call() throws Exception {
482
                    Iterable<? extends Pair<URL, LayeredDocumentIndex>> indices = qs.indexerQuery.getIndices(qs.roots);
483
                    // check if there are stale indices
484
                    for (Pair<URL, LayeredDocumentIndex> pair : indices) {
485
                        final LayeredDocumentIndex index = pair.second;
486
                        final Collection<? extends String> staleFiles = index.getDirtyKeys();
487
                        final boolean scanningThread = RunWhenScanFinishedSupport.isScanningThread();
488
                        LOG.log(
489
                            Level.FINE,
490
                            "Index: {0}, staleFiles: {1}, scanning thread: {2}",  //NOI18N
491
                            new Object[]{
492
                                index,
493
                                staleFiles,
494
                                scanningThread
495
                            });
496
                        if (!staleFiles.isEmpty() && !scanningThread) {
497
                            final URL root = pair.first;
498
                            LinkedList<URL> list = new LinkedList<URL>();
499
                            for (String staleFile : staleFiles) {
500
                                try {
501
                                    list.add(Util.resolveUrl(root, staleFile, false));
502
                                } catch (MalformedURLException ex) {
503
                                    LOG.log(Level.WARNING, null, ex);
504
                                }
505
                            }
506
                            TransientUpdateSupport.setTransientUpdate(true);
507
                            try {
508
                                RepositoryUpdater.getDefault().enforcedFileListUpdate(root,list);
509
                            } finally {
510
                                TransientUpdateSupport.setTransientUpdate(false);
511
                            }
512
                        }
513
                    }
514
                    final Queue<IndexResult> result = new ArrayDeque<IndexResult>();
515
                    for (Pair<URL, LayeredDocumentIndex> pair : indices) {
516
                        final DocumentIndex2 index = pair.second;
517
                        final URL root = pair.first;
518
                        final Collection<? extends IndexResult> pr =
519
                                index.query(
520
                                    queryImpl,
521
                                    new DocumentToResultConvertor(root),
522
                                    fieldsToLoad);
523
                        result.addAll(pr);  //TODO: Perf: Replace by ProxyCollection
524
                        if (LOG.isLoggable(Level.FINE)) {
525
                            LOG.log(
526
                                Level.FINE, "{0} (loading fields {1}) invoked at {2}@{3}[indexer={4}]:",    //NOI18N
527
                                new Object[]{
528
                                    this,
529
                                    printFiledToLoad(fieldsToLoad),
530
                                    qs.getClass().getSimpleName(),
531
                                    Integer.toHexString(System.identityHashCode(qs)),
532
                                    qs.indexerQuery.getIndexerId()});
533
                            for (IndexResult idi : pr) {
534
                                LOG.log(Level.FINE, " {0}", idi); //NOI18N
535
                            }
536
                            LOG.fine("----"); //NOI18N
537
                        }                        
538
                    }
539
                    return result;
540
                }
541
            });
542
        } catch (Index.IndexClosedException ice) {
543
            if (Installer.isClosed()) {
544
                return Collections.<IndexResult>emptySet();
545
            } else {
546
                throw ice;
547
            }
548
        } catch (IOException ioe) {
549
            throw ioe;
550
        } catch (RuntimeException re) {
551
            throw re;
552
        } catch (Exception ex) {
553
            throw new IOException(ex);
554
        }
555
            
556
        }
557
558
        @NonNull
559
        @Override
560
        public String toString() {
561
            return String.format(
562
                "QuerySupport.Query[%s]",   //NOI18N
563
                queryImpl);
564
        }        
565
    }
566
436
    // ------------------------------------------------------------------------
567
    // ------------------------------------------------------------------------
437
    // Private implementation
568
    // Private implementation
438
    // ------------------------------------------------------------------------
569
    // ------------------------------------------------------------------------
Lines 720-723 Link Here
720
            return null;
851
            return null;
721
        }        
852
        }        
722
    } // End of IndexerQuery class
853
    } // End of IndexerQuery class
854
855
    private static final class DocumentToResultConvertor implements Convertor<IndexDocument, IndexResult> {
856
857
        private final URL root;
858
859
        DocumentToResultConvertor(@NonNull final URL root) {
860
            this.root = root;
861
        }
862
863
        @Override
864
        @CheckForNull
865
        public IndexResult convert(@NullAllowed final IndexDocument p) {
866
            return p == null ?
867
                null :
868
                new IndexResult(p, root);
869
        }
870
871
    }
723
}
872
}
(-)a/parsing.api/test/unit/src/org/netbeans/modules/parsing/spi/indexing/support/IndexingSupportTest.java (+180 lines)
Lines 80-85 Link Here
80
    private FileObject cache;
80
    private FileObject cache;
81
    private FileObject f1;
81
    private FileObject f1;
82
    private FileObject f2;
82
    private FileObject f2;
83
    private FileObject f3;
84
    private FileObject f4;
83
85
84
    public IndexingSupportTest (final String name) {
86
    public IndexingSupportTest (final String name) {
85
        super (name);
87
        super (name);
Lines 100-105 Link Here
100
        assert f1 != null;
102
        assert f1 != null;
101
        f2 = FileUtil.createData(root,"folder/b.foo");
103
        f2 = FileUtil.createData(root,"folder/b.foo");
102
        assert f2 != null;
104
        assert f2 != null;
105
        f3 = FileUtil.createData(root,"folder/c.foo");
106
        assert f3 != null;
107
        f4 = FileUtil.createData(root,"folder/c.foo");
108
        assert f4 != null;
103
        FileUtil.setMIMEType("foo", MIME);  //NOI18N
109
        FileUtil.setMIMEType("foo", MIME);  //NOI18N
104
    }
110
    }
105
111
Lines 224-229 Link Here
224
        assertEquals("true", ir[1].getValue("flag"));
230
        assertEquals("true", ir[1].getValue("flag"));
225
    }
231
    }
226
232
233
234
    public void testIndexingQuerySupport2 () throws Exception {
235
        // index
236
        final Context ctx = SPIAccessor.getInstance().createContext(
237
                CacheFolder.getDataFolder(root.toURL()),
238
                root.toURL(),
239
                "fooIndexer",
240
                1,
241
                null,
242
                false,
243
                false,
244
                false,
245
                SuspendSupport.NOP,
246
                null,
247
                null);
248
        assertNotNull(ctx);
249
        final Indexable i1 = SPIAccessor.getInstance().create(new FileObjectIndexable(root, f1));
250
        final IndexingSupport is = IndexingSupport.getInstance(ctx);
251
        assertNotNull(is);
252
        IndexDocument doc1 = is.createDocument(i1);
253
        assertNotNull(doc1);
254
        doc1.addPair("class", "String", true, true);
255
        doc1.addPair("package", "java.lang", true, true);
256
        is.addDocument(doc1);
257
        final Indexable i2 = SPIAccessor.getInstance().create(new FileObjectIndexable(root, f2));
258
        IndexDocument doc2 = is.createDocument(i2);
259
        assertNotNull(doc2);
260
        doc2.addPair("class", "Object", true, true);
261
        doc2.addPair("package", "java.lang", true, true);
262
        doc2.addPair("flag", "true", true, true);
263
        is.addDocument(doc2);
264
        SPIAccessor.getInstance().getIndexFactory(ctx).getIndex(ctx.getIndexFolder()).store(true);
265
266
        // query
267
        QuerySupport qs = QuerySupport.forRoots("fooIndexer", 1, root);
268
        Collection<? extends IndexResult> result = qs.getQueryFactory().field("class", "String", QuerySupport.Kind.EXACT).execute("class", "package");
269
        assertEquals(1, result.size());
270
        assertEquals("String", result.iterator().next().getValue("class"));
271
        assertEquals("java.lang", result.iterator().next().getValue("package"));
272
        assertEquals(f1, result.iterator().next().getFile());
273
        assertEquals(f1.getURL(), result.iterator().next().getUrl());
274
        result = qs.getQueryFactory().field("class", "Str", QuerySupport.Kind.PREFIX).execute("class", "package");
275
        assertEquals(1, result.size());
276
        assertEquals("String", result.iterator().next().getValue("class"));
277
        assertEquals("java.lang", result.iterator().next().getValue("package"));
278
        result = qs.getQueryFactory().field("class", "S.*g", QuerySupport.Kind.REGEXP).execute("class", "package");
279
        assertEquals(1, result.size());
280
        assertEquals("String", result.iterator().next().getValue("class"));
281
        assertEquals("java.lang", result.iterator().next().getValue("package"));
282
        result = qs.getQueryFactory().field("class", "S", QuerySupport.Kind.CAMEL_CASE).execute("class", "package");
283
        assertEquals(1, result.size());
284
        assertEquals("String", result.iterator().next().getValue("class"));
285
        assertEquals("java.lang", result.iterator().next().getValue("package"));
286
        result = qs.getQueryFactory().field("class", "", QuerySupport.Kind.PREFIX).execute("class", "package");
287
        assertEquals(2, result.size());
288
        IndexResult[] ir = new IndexResult[2];
289
        ir = result.toArray(ir);
290
        assertEquals("String", ir[0].getValue("class"));
291
        assertEquals("java.lang", ir[0].getValue("package"));
292
        assertEquals("Object", ir[1].getValue("class"));
293
        assertEquals("java.lang", ir[1].getValue("package"));
294
        result = qs.getQueryFactory().field("class", "F", QuerySupport.Kind.PREFIX).execute("class", "package");
295
        assertEquals(0, result.size());
296
297
        // search for documents that contain field called 'flag'
298
        result = qs.getQueryFactory().field("flag", "", QuerySupport.Kind.PREFIX).execute();
299
        assertEquals(1, result.size());
300
        assertEquals("Object", result.iterator().next().getValue("class"));
301
        assertEquals("java.lang", result.iterator().next().getValue("package"));
302
        assertEquals("true", result.iterator().next().getValue("flag"));
303
304
        // search for all documents
305
        result = qs.getQueryFactory().field("", "", QuerySupport.Kind.PREFIX).execute();
306
        assertEquals(2, result.size());
307
        ir = new IndexResult[2];
308
        ir = result.toArray(ir);
309
        assertEquals("String", ir[0].getValue("class"));
310
        assertEquals("java.lang", ir[0].getValue("package"));
311
        assertNull(ir[0].getValue("flag"));
312
        assertEquals("Object", ir[1].getValue("class"));
313
        assertEquals("java.lang", ir[1].getValue("package"));
314
        assertEquals("true", ir[1].getValue("flag"));
315
    }
316
317
    public void testIndexingQuerySupport3 () throws Exception {
318
        // index
319
        final Context ctx = SPIAccessor.getInstance().createContext(
320
                CacheFolder.getDataFolder(root.toURL()),
321
                root.toURL(),
322
                "fooIndexer",
323
                1,
324
                null,
325
                false,
326
                false,
327
                false,
328
                SuspendSupport.NOP,
329
                null,
330
                null);
331
        assertNotNull(ctx);
332
        final Indexable i1 = SPIAccessor.getInstance().create(new FileObjectIndexable(root, f1));
333
        final IndexingSupport is = IndexingSupport.getInstance(ctx);
334
        assertNotNull(is);
335
        IndexDocument doc1 = is.createDocument(i1);
336
        assertNotNull(doc1);
337
        doc1.addPair("class", "String", true, true);
338
        doc1.addPair("package", "java.lang", true, true);
339
        is.addDocument(doc1);
340
        final Indexable i2 = SPIAccessor.getInstance().create(new FileObjectIndexable(root, f2));
341
        IndexDocument doc2 = is.createDocument(i2);
342
        assertNotNull(doc2);
343
        doc2.addPair("class", "Object", true, true);
344
        doc2.addPair("package", "java.lang", true, true);
345
        is.addDocument(doc2);
346
        final Indexable i3 = SPIAccessor.getInstance().create(new FileObjectIndexable(root, f3));
347
        IndexDocument doc3 = is.createDocument(i3);
348
        assertNotNull(doc3);
349
        doc3.addPair("class", "Object", true, true);
350
        doc3.addPair("package", "org.omg.CORBA", true, true);
351
        is.addDocument(doc3);
352
        final Indexable i4 = SPIAccessor.getInstance().create(new FileObjectIndexable(root, f4));
353
        IndexDocument doc4 = is.createDocument(i3);
354
        assertNotNull(doc4);
355
        doc4.addPair("class", "Integer", true, true);
356
        doc4.addPair("package", "java.lang", true, true);
357
        is.addDocument(doc4);
358
        SPIAccessor.getInstance().getIndexFactory(ctx).getIndex(ctx.getIndexFolder()).store(true);
359
360
        // query
361
        QuerySupport qs = QuerySupport.forRoots("fooIndexer", 1, root);
362
        Collection<? extends IndexResult> result = qs.getQueryFactory().field("class", "Object", QuerySupport.Kind.EXACT).execute("class", "package");
363
        assertEquals(2, result.size());
364
        IndexResult[] ir = result.toArray(new IndexResult[2]);
365
        assertEquals("Object", ir[0].getValue("class"));
366
        assertEquals("java.lang", ir[0].getValue("package"));
367
        assertEquals("Object", ir[1].getValue("class"));
368
        assertEquals("org.omg.CORBA", ir[1].getValue("package"));
369
        result = qs.getQueryFactory().
370
                and(
371
                    qs.getQueryFactory().field("class", "Object", QuerySupport.Kind.EXACT),
372
                    qs.getQueryFactory().field("package", "org.omg.CORBA", QuerySupport.Kind.EXACT)).execute("class", "package");
373
        assertEquals(1, result.size());
374
        ir = result.toArray(new IndexResult[1]);
375
        assertEquals("Object", ir[0].getValue("class"));        
376
        assertEquals("org.omg.CORBA", ir[0].getValue("package"));
377
        result = qs.getQueryFactory().
378
                and(
379
                    qs.getQueryFactory().field("package", "java.lang", QuerySupport.Kind.EXACT),
380
                    qs.getQueryFactory().or(
381
                        qs.getQueryFactory().field("class", "String", QuerySupport.Kind.EXACT),
382
                        qs.getQueryFactory().field("class", "Integer", QuerySupport.Kind.EXACT))
383
                ).execute("class", "package");
384
        assertEquals(2, result.size());
385
        ir = result.toArray(new IndexResult[2]);
386
        assertEquals("String", ir[0].getValue("class"));
387
        assertEquals("java.lang", ir[0].getValue("package"));
388
        assertEquals("Integer", ir[1].getValue("class"));
389
        assertEquals("java.lang", ir[1].getValue("package"));
390
        result = qs.getQueryFactory().
391
                or(
392
                    qs.getQueryFactory().and(
393
                        qs.getQueryFactory().field("package", "java.lang", QuerySupport.Kind.EXACT),
394
                        qs.getQueryFactory().field("class", "String", QuerySupport.Kind.EXACT)),
395
                    qs.getQueryFactory().and(
396
                        qs.getQueryFactory().field("package", "java.lang", QuerySupport.Kind.EXACT),
397
                        qs.getQueryFactory().field("class", "Integer", QuerySupport.Kind.EXACT))
398
                ).execute("class", "package");
399
        assertEquals(2, result.size());
400
        ir = result.toArray(new IndexResult[2]);
401
        assertEquals("String", ir[0].getValue("class"));
402
        assertEquals("java.lang", ir[0].getValue("package"));
403
        assertEquals("Integer", ir[1].getValue("class"));
404
        assertEquals("java.lang", ir[1].getValue("package"));  
405
    }
406
227
    public void testQuerySupportCaching() throws Exception {
407
    public void testQuerySupportCaching() throws Exception {
228
        // index
408
        // index
229
        final Context ctx = SPIAccessor.getInstance().createContext(
409
        final Context ctx = SPIAccessor.getInstance().createContext(
(-)a/parsing.lucene/apichanges.xml (+15 lines)
Lines 110-115 Link Here
110
<!-- ACTUAL CHANGES BEGIN HERE: -->
110
<!-- ACTUAL CHANGES BEGIN HERE: -->
111
111
112
  <changes>
112
  <changes>
113
  <change id="DocumentIndex2">
114
    <api name="LuceneSupport"/>
115
    <summary>Added <code>DocumentIndex2</code> allowing execution of arbitrary Lucene query.</summary>
116
    <version major="2" minor="24"/>
117
    <date day="2" month="5" year="2013"/>
118
    <author login="tzezula"/>
119
    <compatibility source="compatible" binary="compatible" addition="yes"/>
120
    <description>
121
        <p>
122
            Added <code>DocumentIndex2</code> extending the <code>DocumentIndex</code> by execution of arbitrary Lucene query.
123
        </p>
124
    </description>
125
    <class package="org.netbeans.modules.parsing.lucene.support" name="DocumentIndex2"/>
126
    <class package="org.netbeans.modules.parsing.lucene.support" name="Convertors"/>
127
  </change>
113
  <change id="DocumentIndexCache-WithCustomIndexDocument">
128
  <change id="DocumentIndexCache-WithCustomIndexDocument">
114
    <api name="LuceneSupport"/>
129
    <api name="LuceneSupport"/>
115
    <summary>Added possibility to use the default <code>DocumentIndex</code> with custom <code>IndexDocument</code>s.</summary>
130
    <summary>Added possibility to use the default <code>DocumentIndex</code> with custom <code>IndexDocument</code>s.</summary>
(-)a/parsing.lucene/nbproject/project.properties (-1 / +1 lines)
Lines 3-9 Link Here
3
javadoc.apichanges=${basedir}/apichanges.xml
3
javadoc.apichanges=${basedir}/apichanges.xml
4
javac.compilerargs=-Xlint -Xlint:-serial
4
javac.compilerargs=-Xlint -Xlint:-serial
5
5
6
spec.version.base=2.23.0
6
spec.version.base=2.24.0
7
test.config.stableBTD.includes=**/*Test.class
7
test.config.stableBTD.includes=**/*Test.class
8
test.config.stableBTD.excludes=\
8
test.config.stableBTD.excludes=\
9
    **/LuceneIndexTest.class
9
    **/LuceneIndexTest.class
(-)a/parsing.lucene/src/org/netbeans/modules/parsing/lucene/DocumentIndexImpl.java (-17 / +40 lines)
Lines 43-52 Link Here
43
package org.netbeans.modules.parsing.lucene;
43
package org.netbeans.modules.parsing.lucene;
44
44
45
import java.io.IOException;
45
import java.io.IOException;
46
import java.util.ArrayList;
46
import java.util.ArrayDeque;
47
import java.util.Collection;
47
import java.util.Collection;
48
import java.util.HashSet;
48
import java.util.HashSet;
49
import java.util.ArrayList;
49
import java.util.ArrayList;
50
import java.util.Arrays;
50
import java.util.List;
51
import java.util.List;
51
import java.util.Set;
52
import java.util.Set;
52
import java.util.concurrent.atomic.AtomicBoolean;
53
import java.util.concurrent.atomic.AtomicBoolean;
Lines 56-74 Link Here
56
import org.apache.lucene.document.FieldSelector;
57
import org.apache.lucene.document.FieldSelector;
57
import org.apache.lucene.search.Query;
58
import org.apache.lucene.search.Query;
58
import org.netbeans.api.annotations.common.NonNull;
59
import org.netbeans.api.annotations.common.NonNull;
60
import org.netbeans.api.annotations.common.NullAllowed;
59
import org.netbeans.modules.parsing.lucene.support.Convertor;
61
import org.netbeans.modules.parsing.lucene.support.Convertor;
60
import org.netbeans.modules.parsing.lucene.support.DocumentIndex;
62
import org.netbeans.modules.parsing.lucene.support.DocumentIndex2;
61
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
63
import org.netbeans.modules.parsing.lucene.support.DocumentIndexCache;
62
import org.netbeans.modules.parsing.lucene.support.Index;
64
import org.netbeans.modules.parsing.lucene.support.Index;
63
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
65
import org.netbeans.modules.parsing.lucene.support.IndexDocument;
64
import org.netbeans.modules.parsing.lucene.support.Queries;
66
import org.netbeans.modules.parsing.lucene.support.Queries;
65
import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
67
import org.netbeans.modules.parsing.lucene.support.Queries.QueryKind;
68
import org.openide.util.Parameters;
66
69
67
/**
70
/**
68
 *
71
 *
69
 * @author Tomas Zezula
72
 * @author Tomas Zezula
70
 */
73
 */
71
public class DocumentIndexImpl implements DocumentIndex, Runnable {
74
public class DocumentIndexImpl implements DocumentIndex2, Runnable {
72
                            
75
                            
73
    private static final Convertor<IndexDocument,Document> DEFAULT_ADD_CONVERTOR = Convertors.newIndexDocumentToDocumentConvertor();    
76
    private static final Convertor<IndexDocument,Document> DEFAULT_ADD_CONVERTOR = Convertors.newIndexDocumentToDocumentConvertor();    
74
    private static final Convertor<Document,IndexDocumentImpl> DEFAULT_QUERY_CONVERTOR = Convertors.newDocumentToIndexDocumentConvertor();
77
    private static final Convertor<Document,IndexDocumentImpl> DEFAULT_QUERY_CONVERTOR = Convertors.newDocumentToIndexDocumentConvertor();
Lines 248-264 Link Here
248
        assert fieldName != null;
251
        assert fieldName != null;
249
        assert value != null;
252
        assert value != null;
250
        assert kind != null;
253
        assert kind != null;
251
        final List<IndexDocument> result = new ArrayList<IndexDocument>();
252
        final Query query = Queries.createQuery(fieldName, fieldName, value, kind);
254
        final Query query = Queries.createQuery(fieldName, fieldName, value, kind);
253
        FieldSelector selector = null;
255
        return query(
254
        if (fieldsToLoad != null && fieldsToLoad.length > 0) {
256
            query,
255
            final String[] fieldsWithSource = new String[fieldsToLoad.length+1];
257
            org.netbeans.modules.parsing.lucene.support.Convertors.<IndexDocument>identity(),
256
            System.arraycopy(fieldsToLoad, 0, fieldsWithSource, 0, fieldsToLoad.length);
258
            fieldsToLoad);
257
            fieldsWithSource[fieldsToLoad.length] = IndexDocumentImpl.FIELD_PRIMARY_KEY;
258
            selector = Queries.createFieldSelector(fieldsWithSource);
259
        }        
260
        luceneIndex.query(result, queryConvertor, selector, null, query);
261
        return result;
262
    }
259
    }
263
    
260
    
264
    @Override
261
    @Override
Lines 270-275 Link Here
270
    }
267
    }
271
268
272
    @Override
269
    @Override
270
    @NonNull
271
    public <T> Collection<? extends T> query(
272
            @NonNull final Query query,
273
            @NonNull final Convertor<? super IndexDocument, ? extends T> convertor,
274
            @NullAllowed final String... fieldsToLoad) throws IOException, InterruptedException {
275
        Parameters.notNull("query", query); //NOI18N
276
        Parameters.notNull("convertor", convertor); //NOI18N
277
        final Collection<T> result = new ArrayDeque<T>();
278
        FieldSelector selector = null;
279
        if (fieldsToLoad != null && fieldsToLoad.length > 0) {
280
            final String[] fieldsWithSource = Arrays.copyOf(fieldsToLoad, fieldsToLoad.length+1);
281
            fieldsWithSource[fieldsToLoad.length] = IndexDocumentImpl.FIELD_PRIMARY_KEY;
282
            selector = Queries.createFieldSelector(fieldsWithSource);
283
        }
284
        luceneIndex.query(
285
            result,
286
            org.netbeans.modules.parsing.lucene.support.Convertors.compose(queryConvertor, convertor),
287
            selector,
288
            null,
289
            query);
290
        return result;
291
    }
292
293
    @Override
273
    public void markKeyDirty(final String primaryKey) {
294
    public void markKeyDirty(final String primaryKey) {
274
        synchronized (this) {
295
        synchronized (this) {
275
            if (LOGGER.isLoggable(Level.FINE)) {
296
            if (LOGGER.isLoggable(Level.FINE)) {
Lines 302-325 Link Here
302
    
323
    
303
    @Override
324
    @Override
304
    public String toString () {
325
    public String toString () {
305
        return "DocumentIndex["+luceneIndex.toString()+"]";  //NOI18N
326
        return String.format(
327
            "DocumentIndexImpl[%s]",  //NOI18N
328
            luceneIndex.toString());
306
    }
329
    }
307
330
308
    @NonNull
331
    @NonNull
309
    public static DocumentIndex create(
332
    public static DocumentIndex2 create(
310
            @NonNull final Index index,
333
            @NonNull final Index index,
311
            @NonNull final DocumentIndexCache cache) {
334
            @NonNull final DocumentIndexCache cache) {
312
        return new DocumentIndexImpl(index, cache);
335
        return new DocumentIndexImpl(index, cache);
313
    }
336
    }
314
337
315
    @NonNull
338
    @NonNull
316
    public static DocumentIndex.Transactional createTransactional(
339
    public static DocumentIndex2.Transactional createTransactional(
317
            @NonNull final Index.Transactional index,
340
            @NonNull final Index.Transactional index,
318
            @NonNull final DocumentIndexCache cache) {
341
            @NonNull final DocumentIndexCache cache) {
319
        return new DocumentIndexImpl.Transactional(index, cache);
342
        return new DocumentIndexImpl.Transactional(index, cache);
320
    }
343
    }
321
344
322
    private final static class Transactional extends DocumentIndexImpl implements DocumentIndex.Transactional {
345
    private final static class Transactional extends DocumentIndexImpl implements DocumentIndex2.Transactional {
323
346
324
        private Transactional(
347
        private Transactional(
325
            @NonNull final Index.Transactional index,
348
            @NonNull final Index.Transactional index,
(-)a/parsing.lucene/src/org/netbeans/modules/parsing/lucene/support/Convertors.java (+119 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.parsing.lucene.support;
43
44
import org.netbeans.api.annotations.common.CheckForNull;
45
import org.netbeans.api.annotations.common.NonNull;
46
import org.netbeans.api.annotations.common.NullAllowed;
47
import org.openide.util.Parameters;
48
49
/**
50
 * {@link Convertor} utilities.
51
 * @author Tomas Zezula
52
 * @since 2.24
53
 */
54
public final class Convertors {
55
    
56
    private static final Convertor<?,?> IDENTITY =
57
            new Convertor<Object, Object>() {
58
                @Override
59
                @CheckForNull
60
                public Object convert(@NullAllowed final Object p) {
61
                    return p;
62
                }
63
            };
64
65
    private Convertors() {}
66
67
    /**
68
     * Identity convertor.
69
     * Returns the identity function, function returning its parameter.
70
     * @param <T> type of the both parameter and result.
71
     * @return returns identity convertor.
72
     */
73
    @SuppressWarnings("unchecked")
74
    public static <T> Convertor<T,T> identity() {
75
        return (Convertor<T,T>) IDENTITY;
76
    }
77
78
    /**
79
     * Composite convertor.
80
     * Returns the composition of two functions F(p)->second(first(p)).
81
     * @param <P> the parameter type of the first {@link Convertor}
82
     * @param <I> the result type of the first {@link Convertor}
83
     * @param <R> the result type of the second {@link Convertor}
84
     * @param first the first {@link Convertor}
85
     * @param second the second {@link Convertor}
86
     * @return the composite {@link Convertor}
87
     */
88
    public static <P,I,R> Convertor <P,R> compose(
89
            @NonNull final Convertor<? super P, ? extends I> first,
90
            @NonNull final Convertor<? super I, ? extends R> second) {
91
        Parameters.notNull("first", first); //NOI18N
92
        Parameters.notNull("second", second); //NOI18N
93
        return new CompositeConvertor<P,I,R> (first, second);
94
    }
95
96
97
98
    private static final class CompositeConvertor<P,I,R> implements Convertor<P, R> {
99
100
        private final Convertor<? super P, ? extends I> first;
101
        private final Convertor<? super I, ? extends R> second;
102
103
        CompositeConvertor(
104
            @NonNull final Convertor<? super P, ? extends I> first,
105
            @NonNull final Convertor<? super I, ? extends R> second) {
106
            this.first = first;
107
            this.second = second;
108
        }
109
110
111
        @Override
112
        @CheckForNull
113
        public R convert(@NullAllowed P p) {
114
            return second.convert(first.convert(p));
115
        }
116
117
    }
118
119
}
(-)a/parsing.lucene/src/org/netbeans/modules/parsing/lucene/support/DocumentIndex2.java (+76 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2013 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.parsing.lucene.support;
43
44
import java.io.IOException;
45
import java.util.Collection;
46
import org.apache.lucene.search.Query;
47
import org.netbeans.api.annotations.common.NonNull;
48
import org.netbeans.api.annotations.common.NullAllowed;
49
50
/**
51
 * Document based index allowing arbitrary Lucene Query.
52
 * @author Tomas Zezula
53
 * @since 2.24
54
 */
55
public interface DocumentIndex2 extends DocumentIndex {
56
57
    /**
58
     * Performs the Lucene query on the index.
59
     * @param query to perform
60
     * @param fieldsToLoad  fields to load into returned document
61
     * @return  the Collection of {@link IndexDocument} matching the query.
62
     * @throws IOException  in case of IO error.
63
     * @throws InterruptedException if the search is interrupted.
64
     */
65
    @NonNull
66
    public  <T> Collection<? extends T> query (
67
            @NonNull Query query,
68
            @NonNull Convertor<? super IndexDocument, ? extends T> convertor,
69
            @NullAllowed String... fieldsToLoad) throws IOException, InterruptedException;
70
71
    /**
72
     * Transactional {@link DocumentIndex2}.
73
     */
74
    public interface  Transactional extends DocumentIndex2, DocumentIndex.Transactional {
75
    }
76
}

Return to bug 229059