KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > ruby > RubyIndex


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.ruby;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.net.MalformedURLException JavaDoc;
24 import java.net.MalformedURLException JavaDoc;
25 import java.net.URL JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.EnumSet JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.HashSet JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
32
33 import org.netbeans.api.gsf.Index;
34 import static org.netbeans.api.gsf.Index.*;
35 import org.netbeans.api.gsf.Modifier;
36 import org.netbeans.modules.ruby.elements.IndexedClass;
37 import org.netbeans.modules.ruby.elements.IndexedElement;
38 import org.netbeans.modules.ruby.elements.IndexedMethod;
39 import org.openide.filesystems.FileObject;
40 import org.openide.filesystems.URLMapper;
41 import org.openide.modules.InstalledFileLocator;
42 import org.openide.util.Exceptions;
43
44
45 /**
46  * Access to the index of known Ruby classes - core, libraries, gems, user projects, etc.
47  *
48  * @todo Pull out attributes, fields and constants from the index as well
49  * @todo Store signature attributes for methods: private/protected?, documented?, returntype?
50  * @todo When there are multiple method/field definitions, pick access level from one which sets it
51  * @author Tor Norbye
52  */

53 public final class RubyIndex {
54     private static final String JavaDoc OBJECT = "Object"; // NOI18N
55
private static final String JavaDoc CLASS = "Class"; // NOI18N
56
private static final String JavaDoc MODULE = "Module"; // NOI18N
57
private static final Set JavaDoc<SearchScope> ALL_SCOPE = EnumSet.allOf(SearchScope.class);
58
59     private static String JavaDoc clusterUrl = null;
60     private static final String JavaDoc CLUSTER_URL = "cluster:"; // NOI18N
61
private Index index;
62
63     /** Creates a new instance of RubyIndex */
64     public RubyIndex(Index index) {
65         this.index = index;
66     }
67
68     public static RubyIndex get(Index index) {
69         return new RubyIndex(index);
70     }
71
72     private boolean search(String JavaDoc key, String JavaDoc name, NameKind kind, Set JavaDoc<SearchResult> result) {
73         try {
74             index.gsfSearch(key, name, kind, ALL_SCOPE, result);
75
76             return true;
77         } catch (IOException JavaDoc ioe) {
78             Exceptions.printStackTrace(ioe);
79
80             return false;
81         }
82     }
83
84     /**
85      * Return the full set of classes that match the given name.
86      *
87      * @param name The name of the class - possibly a fqn like File::Stat, or just a class
88      * name like Stat, or just a prefix like St.
89      * @param kind Whether we want the exact name, or whether we're searching by a prefix.
90      * @param includeAll If true, return multiple RuIndexedClassnstances for the same logical
91      * class, one for each declaration point. For example, File is defined both in the
92      * builtin stubs as well as in ftools.
93      */

94     public Set JavaDoc<IndexedClass> getClasses(String JavaDoc name, final NameKind kind, boolean includeAll,
95         boolean skipClasses, boolean skipModules) {
96         String JavaDoc classFqn = null;
97
98         if (name != null) {
99             if (name.indexOf("::") != -1) { // NOI18N
100

101                 int p = name.lastIndexOf("::"); // NOI18N
102
classFqn = name.substring(0, p);
103                 name = name.substring(p + 2);
104             } else if (name.endsWith(":")) {
105                 // User has typed something like "Test:" and wants completion on
106
// for something like Test::Unit
107
classFqn = name.substring(0, name.length() - 1);
108                 name = "";
109             }
110         }
111
112         final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
113
114         // if (!isValid()) {
115
// LOGGER.fine(String.format("LuceneIndex[%s] is invalid!\n", this.toString()));
116
// return;
117
// }
118
String JavaDoc field = null;
119
120         switch (kind) {
121         case EXACT_NAME:
122         case PREFIX:
123         case CAMEL_CASE:
124         case REGEXP:
125             field = RubyIndexer.FIELD_CLASS_NAME;
126
127             break;
128
129         case CASE_INSENSITIVE_PREFIX:
130         case CASE_INSENSITIVE_REGEXP:
131             field = RubyIndexer.FIELD_CASE_INSENSITIVE_CLASS_NAME;
132
133             break;
134
135         default:
136             throw new UnsupportedOperationException JavaDoc(kind.toString());
137         }
138
139         search(field, name, kind, result);
140
141         // TODO Prune methods to fit my scheme - later make lucene index smarter about how to prune its index search
142
final Set JavaDoc<String JavaDoc> uniqueClasses;
143
144         if (includeAll) {
145             uniqueClasses = null;
146         } else {
147             uniqueClasses = new HashSet JavaDoc<String JavaDoc>(); // TODO : init inside includeAll check
148
}
149
150         final Set JavaDoc<IndexedClass> classes = new HashSet JavaDoc<IndexedClass>();
151
152         for (SearchResult map : result) {
153             String JavaDoc clz = map.getValue(RubyIndexer.FIELD_CLASS_NAME);
154
155             if (clz == null) {
156                 // It's probably a module
157
// XXX I need to handle this... for now punt
158
continue;
159             }
160
161             // Lucene returns some inexact matches, TODO investigate why this is necessary
162
if ((kind == NameKind.PREFIX) && !clz.startsWith(name)) {
163                 continue;
164             }
165
166             if ((classFqn != null) && !classFqn.equals(map.getValue(RubyIndexer.FIELD_IN))) {
167                 continue;
168             }
169
170             String JavaDoc attrs = map.getValue(RubyIndexer.FIELD_CLASS_ATTRS);
171             boolean isClass = attrs.charAt(0) == 'C';
172
173             if (skipClasses && isClass) {
174                 continue;
175             }
176
177             if (skipModules && !isClass) {
178                 continue;
179             }
180
181             String JavaDoc fqn = map.getValue(RubyIndexer.FIELD_FQN_NAME);
182
183             // Only return a single instance for this signature
184
if (!includeAll) {
185                 if (uniqueClasses.contains(fqn)) { // use a map to point right to the class
186
// Prefer the instance that provides documentation
187

188                     boolean replaced = false;
189                     int documentedAt = attrs.indexOf('d');
190                     boolean isDocumented = documentedAt != -1;
191
192                     if (isDocumented) {
193                         // Check the actual size of the documentation, and prefer the largest
194
// method
195
int length = 0;
196                         documentedAt = attrs.indexOf('(', documentedAt + 1);
197
198                         if (documentedAt != -1) {
199                             length = Integer.parseInt(attrs.substring(documentedAt + 1,
200                                         attrs.indexOf(')', documentedAt + 1)));
201                         }
202
203                         // This instance is documented. Replace the other instance...
204
for (IndexedClass c : classes) {
205                             if (c.getSignature().equals(fqn) &&
206                                     (length > c.getDocumentationLength())) {
207                                 classes.remove(c);
208                                 replaced = true;
209
210                                 break;
211                             }
212                         }
213                     }
214
215                     if (!replaced) {
216                         continue;
217                     }
218                 } else {
219                     uniqueClasses.add(fqn);
220                 }
221             }
222
223             classes.add(createClass(fqn, clz, map));
224         }
225
226         return classes;
227     }
228
229     /**
230      * Return a set of methods that match the given name prefix, and are in the given
231      * class and module. If no class is specified, match methods across all classes.
232      * Note that inherited methods are not checked. If you want to match inherited methods
233      * you must call this method on each superclass as well as the mixin modules.
234      */

235     @SuppressWarnings JavaDoc("unchecked") // NOI18N, unchecked - lucene has source 1.4
236

237     public Set JavaDoc<IndexedMethod> getMethods(final String JavaDoc name, final String JavaDoc clz, NameKind kind) {
238         // public void searchByCriteria(final String name, final ClassIndex.NameKind kind, /*final ResultConvertor<T> convertor,*/ final Set<String> result) throws IOException {
239
final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
240
241         // if (!isValid()) {
242
// LOGGER.fine(String.format("LuceneIndex[%s] is invalid!\n", this.toString()));
243
// return;
244
// }
245
String JavaDoc field = null;
246         NameKind originalKind = kind;
247
248         switch (kind) {
249         // No point in doing case insensitive searches on method names because
250
// method names in Ruby are always case insensitive anyway
251
// case CASE_INSENSITIVE_PREFIX:
252
// case CASE_INSENSITIVE_REGEXP:
253
// field = RubyIndexer.FIELD_CASE_INSENSITIVE_METHOD_NAME;
254
// break;
255
case EXACT_NAME:
256             // I can't do exact searches on methods because the method
257
// entries include signatures etc. So turn this into a prefix
258
// search and then compare chopped off signatures with the name
259
kind = NameKind.PREFIX;
260
261         case PREFIX:
262         case CAMEL_CASE:
263         case REGEXP:
264         case CASE_INSENSITIVE_PREFIX:
265         case CASE_INSENSITIVE_REGEXP:
266             field = RubyIndexer.FIELD_METHOD_NAME;
267
268             break;
269
270         default:
271             throw new UnsupportedOperationException JavaDoc(kind.toString());
272         }
273
274         search(field, name, kind, result);
275
276         //return Collections.unmodifiableSet(result);
277

278         // TODO Prune methods to fit my scheme - later make lucene index smarter about how to prune its index search
279
final Set JavaDoc<IndexedMethod> methods = new HashSet JavaDoc<IndexedMethod>();
280
281         for (SearchResult map : result) {
282             if (clz != null) {
283                 String JavaDoc fqn = map.getValue(RubyIndexer.FIELD_FQN_NAME);
284
285                 if (!(clz.equals(fqn))) {
286                     continue;
287                 }
288             }
289
290             String JavaDoc[] signatures = map.getValues(RubyIndexer.FIELD_METHOD_NAME);
291
292             if (signatures != null) {
293                 for (String JavaDoc signature : signatures) {
294                     // Skip weird methods... Think harder about this
295
if (((name == null) || (name.length() == 0)) &&
296                             !Character.isLowerCase(signature.charAt(0))) {
297                         continue;
298                     }
299
300                     // Lucene returns some inexact matches, TODO investigate why this is necessary
301
if ((kind == NameKind.PREFIX) && !signature.startsWith(name)) {
302                         continue;
303                     } else if (originalKind == NameKind.EXACT_NAME) {
304                         // Make sure the name matches exactly
305
// We know that the prefix is correct from the first part of
306
// this if clause, by the signature may have more
307
if (((signature.length() > name.length()) &&
308                                 (signature.charAt(name.length()) != '(')) &&
309                                 (signature.charAt(name.length()) != ':')) {
310                             continue;
311                         }
312                     }
313
314                     // XXX THIS DOES NOT WORK WHEN THERE ARE IDENTICAL SIGNATURES!!!
315
assert map != null;
316                     methods.add(createMethod(signature, map));
317                 }
318             }
319         }
320
321         return methods;
322     }
323
324     private IndexedMethod createMethod(String JavaDoc signature, SearchResult map) {
325         String JavaDoc clz = map.getValue(RubyIndexer.FIELD_CLASS_NAME);
326         String JavaDoc module = map.getValue(RubyIndexer.FIELD_IN);
327
328         if (clz == null) {
329             // Module method?
330
clz = module;
331         } else if ((module != null) && (module.length() > 0)) {
332             clz = module + "::" + clz;
333         }
334
335         String JavaDoc fileUrl = map.getValue(RubyIndexer.FIELD_FILENAME);
336         String JavaDoc fqn = map.getValue(RubyIndexer.FIELD_FQN_NAME);
337         String JavaDoc require = map.getValue(RubyIndexer.FIELD_REQUIRE);
338
339         // Extract attributes
340
int attributeIndex = signature.indexOf(':');
341         Set JavaDoc<Modifier> modifiers;
342
343         if (attributeIndex != -1) {
344             modifiers = RubyIndexer.getModifiersFromString(signature, attributeIndex);
345             signature = signature.substring(0, attributeIndex);
346         } else {
347             modifiers = Collections.emptySet();
348         }
349
350         IndexedMethod m =
351             IndexedMethod.create(this, signature, fqn, clz, fileUrl, require, modifiers);
352
353         return m;
354     }
355
356     private IndexedClass createClass(String JavaDoc fqn, String JavaDoc clz, SearchResult map) {
357         String JavaDoc require = map.getValue(RubyIndexer.FIELD_REQUIRE);
358
359         // TODO - how do I determine -which- file to associate with the file?
360
// Perhaps the one that defines initialize() ?
361
String JavaDoc fileUrl = map.getValue(RubyIndexer.FIELD_FILENAME);
362
363         if (clz == null) {
364             clz = map.getValue(RubyIndexer.FIELD_CLASS_NAME);
365         }
366
367         String JavaDoc attrs = map.getValue(RubyIndexer.FIELD_CLASS_ATTRS);
368         boolean isModule = attrs.charAt(0) == 'm';
369         Set JavaDoc<Modifier> modifiers = Collections.emptySet();
370         IndexedClass c =
371             IndexedClass.create(this, clz, fqn, fileUrl, require, isModule, modifiers, attrs);
372
373         return c;
374     }
375
376     // List of String[2]: 0: requirename, 1: fqn
377
public Set JavaDoc<String JavaDoc[]> getRequires(final String JavaDoc name, final NameKind kind) {
378         final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
379
380         String JavaDoc field = RubyIndexer.FIELD_REQUIRE;
381
382         search(field, name, kind, result);
383
384         // TODO Prune methods to fit my scheme - later make lucene index smarter about how to prune its index search
385
final Map JavaDoc<String JavaDoc, String JavaDoc> fqns = new HashMap JavaDoc<String JavaDoc, String JavaDoc>();
386
387         for (SearchResult map : result) {
388             String JavaDoc[] r = map.getValues(field);
389
390             if (r != null) {
391                 for (String JavaDoc require : r) {
392                     // Lucene returns some inexact matches, TODO investigate why this is necessary
393
if ((kind == NameKind.PREFIX) && !require.startsWith(name)) {
394                         continue;
395                     }
396                     assert map != null;
397
398                     // TODO - check if there's a rubygem which captures this
399
// require and if so, remove it
400
String JavaDoc fqn = map.getValue(RubyIndexer.FIELD_FQN_NAME);
401
402                     String JavaDoc there = fqns.get(require);
403
404                     if ((there == null) || ((there != null) && (there.length() < fqn.length()))) {
405                         fqns.put(require, fqn);
406                     }
407                 }
408             }
409         }
410
411         final Set JavaDoc<String JavaDoc[]> requires = new HashSet JavaDoc<String JavaDoc[]>();
412
413         for (String JavaDoc require : fqns.keySet()) {
414             String JavaDoc fqn = fqns.get(require);
415             String JavaDoc[] item = new String JavaDoc[2];
416             item[0] = require;
417             item[1] = fqn;
418             requires.add(item);
419         }
420
421         return requires;
422     }
423
424     public Set JavaDoc<String JavaDoc> getRequiresTransitively(Set JavaDoc<String JavaDoc> requires) {
425         // Not yet implemented - this requires me to index the require-statements in the files
426
return requires;
427     }
428
429     public IndexedClass getSuperclass(String JavaDoc fqn) {
430         final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
431
432         // if (!isValid()) {
433
// LOGGER.fine(String.format("LuceneIndex[%s] is invalid!\n", this.toString()));
434
// return;
435
// }
436
NameKind kind = NameKind.EXACT_NAME;
437         String JavaDoc field = RubyIndexer.FIELD_FQN_NAME;
438
439         search(field, fqn, kind, result);
440
441         for (SearchResult map : result) {
442             assert fqn.equals(map.getValue(RubyIndexer.FIELD_FQN_NAME));
443
444             String JavaDoc extendsClass = map.getValue(RubyIndexer.FIELD_EXTENDS_NAME);
445
446             if (extendsClass != null) {
447                 // Found the class name, now look it up in the index
448
result.clear();
449
450                 if (!search(field, extendsClass, kind, result)) {
451                     return null;
452                 }
453
454                 // There should be exactly one match
455
if (result.size() > 0) {
456                     SearchResult superMap = result.iterator().next();
457                     String JavaDoc superFqn = superMap.getValue(RubyIndexer.FIELD_FQN_NAME);
458
459                     return createClass(superFqn, extendsClass, superMap);
460                 } else {
461                     return null;
462                 }
463             }
464         }
465
466         return null;
467     }
468
469     public Set JavaDoc<IndexedMethod> getInheritedMethods(String JavaDoc classFqn, String JavaDoc prefix) {
470         boolean haveRedirected = false;
471
472         if ((classFqn == null) || classFqn.equals(OBJECT)) {
473             // Redirect inheritance tree to Class to pick up methods in Class and Module
474
classFqn = CLASS;
475             haveRedirected = true;
476         } else if (MODULE.equals(classFqn) || CLASS.equals(classFqn)) {
477             haveRedirected = true;
478         }
479
480         //String field = RubyIndexer.FIELD_FQN_NAME;
481
Set JavaDoc<IndexedMethod> methods = new HashSet JavaDoc<IndexedMethod>();
482         Set JavaDoc<String JavaDoc> scannedClasses = new HashSet JavaDoc<String JavaDoc>();
483         Set JavaDoc<String JavaDoc> seenSignatures = new HashSet JavaDoc<String JavaDoc>();
484
485         addMethodsFromClass(prefix, classFqn, methods, seenSignatures, scannedClasses,
486             haveRedirected);
487
488         return methods;
489     }
490
491     private void addMethodsFromClass(String JavaDoc prefix, String JavaDoc classFqn, Set JavaDoc<IndexedMethod> methods,
492         Set JavaDoc<String JavaDoc> seenSignatures, Set JavaDoc<String JavaDoc> scannedClasses, boolean haveRedirected) {
493         // Prevent problems with circular includes or redundant includes
494
if (scannedClasses.contains(classFqn)) {
495             return;
496         }
497
498         scannedClasses.add(classFqn);
499
500         String JavaDoc field = RubyIndexer.FIELD_FQN_NAME;
501
502         Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
503
504         search(field, classFqn, NameKind.EXACT_NAME, result);
505
506         String JavaDoc extendsClass = null;
507
508         for (SearchResult map : result) {
509             assert map != null;
510
511             if (extendsClass == null) {
512                 extendsClass = map.getValue(RubyIndexer.FIELD_EXTENDS_NAME);
513             }
514
515             String JavaDoc includes = map.getValue(RubyIndexer.FIELD_INCLUDES);
516
517             if (includes != null) {
518                 String JavaDoc[] in = includes.split(",");
519
520                 for (String JavaDoc include : in) {
521                     addMethodsFromClass(prefix, include, methods, seenSignatures, scannedClasses,
522                         haveRedirected);
523                 }
524             }
525
526             String JavaDoc[] signatures = map.getValues(RubyIndexer.FIELD_METHOD_NAME);
527
528             if (signatures != null) {
529                 for (String JavaDoc signature : signatures) {
530                     // Skip weird methods... Think harder about this
531
if (((prefix == null) || (prefix.length() == 0)) &&
532                             !Character.isLowerCase(signature.charAt(0))) {
533                         continue;
534                     }
535
536                     // Prevent duplicates when method is redefined
537
if (!seenSignatures.contains(signature)) {
538                         if ((prefix == null) || signature.startsWith(prefix)) {
539                             seenSignatures.add(signature);
540                             methods.add(createMethod(signature, map));
541                         }
542                     }
543                 }
544             }
545         }
546
547         if (classFqn.equals(OBJECT)) {
548             return;
549         }
550
551         if (extendsClass == null) {
552             if (haveRedirected) {
553                 addMethodsFromClass(prefix, OBJECT, methods, seenSignatures, scannedClasses, true);
554             } else {
555                 // Rather than inheriting directly from object,
556
// let's go via Class (and Module) up to Object
557
addMethodsFromClass(prefix, CLASS, methods, seenSignatures, scannedClasses, true);
558             }
559         } else {
560             addMethodsFromClass(prefix, extendsClass, methods, seenSignatures, scannedClasses,
561                 haveRedirected);
562         }
563     }
564
565     /** Return all the method or class definitions for the given FQN that are documented. */
566     public Set JavaDoc<?extends IndexedElement> getDocumented(final String JavaDoc fqn) {
567         assert (fqn != null) && (fqn.length() > 0);
568
569         int index = fqn.indexOf('#');
570
571         if (index == -1) {
572             // Looking for a class or a module
573
return getDocumentedClasses(fqn);
574         } else {
575             // Looking for a method
576
String JavaDoc clz = fqn.substring(0, index);
577             String JavaDoc method = fqn.substring(index + 1);
578
579             return getDocumentedMethods(clz, method);
580         }
581     }
582
583     private Set JavaDoc<IndexedClass> getDocumentedClasses(final String JavaDoc fqn) {
584         final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
585         String JavaDoc field = RubyIndexer.FIELD_FQN_NAME;
586
587         search(field, fqn, NameKind.EXACT_NAME, result);
588
589         Set JavaDoc<IndexedClass> matches = new HashSet JavaDoc<IndexedClass>();
590
591         for (SearchResult map : result) {
592             assert map != null;
593
594             String JavaDoc attributes = map.getValue(RubyIndexer.FIELD_CLASS_ATTRS);
595
596             if (attributes.indexOf('d') != -1) {
597                 matches.add(createClass(fqn, null, map));
598             }
599         }
600
601         return matches;
602     }
603
604     private Set JavaDoc<IndexedMethod> getDocumentedMethods(final String JavaDoc fqn, String JavaDoc method) {
605         final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
606         String JavaDoc field = RubyIndexer.FIELD_FQN_NAME;
607
608         search(field, fqn, NameKind.EXACT_NAME, result);
609
610         Set JavaDoc<IndexedMethod> matches = new HashSet JavaDoc<IndexedMethod>();
611
612         for (SearchResult map : result) {
613             String JavaDoc[] signatures = map.getValues(RubyIndexer.FIELD_METHOD_NAME);
614
615             if (signatures != null) {
616                 for (String JavaDoc signature : signatures) {
617                     // Skip weird methods... Think harder about this
618
if (((method == null) || (method.length() == 0)) &&
619                             !Character.isLowerCase(signature.charAt(0))) {
620                         continue;
621                     }
622
623                     if (!signature.startsWith(method)) {
624                         continue;
625                     }
626
627                     // Make sure the name matches exactly
628
// We know that the prefix is correct from the first part of
629
// this if clause, by the signature may have more
630
if (((signature.length() > method.length()) &&
631                             (signature.charAt(method.length()) != '(')) &&
632                             (signature.charAt(method.length()) != ':')) {
633                         continue;
634                     }
635
636                     int attributes = signature.indexOf(':', method.length());
637
638                     if (attributes == -1) {
639                         continue;
640                     }
641
642                     if (signature.indexOf('d', attributes + 1) != -1) {
643                         // Method is documented
644
assert map != null;
645                         matches.add(createMethod(signature, map));
646                     }
647                 }
648             }
649         }
650
651         return matches;
652     }
653
654     /** Return the file url corresponding to the given require statement */
655     public String JavaDoc getRequiredFileUrl(final String JavaDoc require) {
656         final Set JavaDoc<SearchResult> result = new HashSet JavaDoc<SearchResult>();
657
658         String JavaDoc field = RubyIndexer.FIELD_REQUIRE;
659
660         search(field, require, NameKind.EXACT_NAME, result);
661
662         // TODO Prune methods to fit my scheme - later make lucene index smarter about how to prune its index search
663
for (SearchResult map : result) {
664             String JavaDoc file = map.getValue(RubyIndexer.FIELD_FILENAME);
665
666             if (file != null) {
667                 return file;
668             }
669         }
670
671         return null;
672     }
673
674     static String JavaDoc getClusterUrl() {
675         if (clusterUrl == null) {
676             File JavaDoc f =
677                 InstalledFileLocator.getDefault()
678                                     .locate("modules/org-netbeans-modules-ruby.jar", null, false); // NOI18N
679

680             if (f == null) {
681                 throw new RuntimeException JavaDoc("Can't find cluster");
682             }
683
684             f = new File JavaDoc(f.getParentFile().getParentFile().getAbsolutePath());
685
686             try {
687                 f = f.getCanonicalFile();
688                 clusterUrl = f.toURI().toURL().toExternalForm();
689             } catch (IOException JavaDoc ioe) {
690                 Exceptions.printStackTrace(ioe);
691             }
692         }
693
694         return clusterUrl;
695     }
696
697     static String JavaDoc getPreindexUrl(String JavaDoc url) {
698         String JavaDoc s = getClusterUrl();
699
700         if (url.startsWith(s)) {
701             url = CLUSTER_URL + "/" + url.substring(s.length());
702         }
703
704         return url;
705     }
706
707     /** Get the FileObject corresponding to a URL returned from the index */
708     public static FileObject getFileObject(String JavaDoc url) {
709         try {
710             if (url.startsWith(CLUSTER_URL)) { // NOI18N
711
url = getClusterUrl() + "/" + url.substring(CLUSTER_URL.length());
712             }
713
714             return URLMapper.findFileObject(new URL JavaDoc(url));
715         } catch (MalformedURLException JavaDoc mue) {
716             Exceptions.printStackTrace(mue);
717         }
718
719         return null;
720     }
721 }
722
Popular Tags