001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.napi.gsfret.source;
043:
044: import java.io.IOException;
045: import java.net.URL;
046: import java.util.HashSet;
047: import java.util.List;
048: import java.util.Map;
049: import java.util.Set;
050: import java.util.logging.Level;
051: import java.util.logging.Logger;
052: import org.netbeans.modules.gsf.api.Index;
053: import org.netbeans.modules.gsf.api.NameKind;
054: import org.netbeans.modules.gsfpath.api.classpath.ClassPath;
055: import org.netbeans.modules.gsf.Language;
056: import org.netbeans.modules.gsfret.source.GlobalSourcePath;
057: import org.netbeans.modules.gsfret.source.usages.ClassIndexFactory;
058: import org.netbeans.modules.gsfret.source.usages.ClassIndexImpl;
059: import org.netbeans.modules.gsfret.source.usages.ClassIndexManager;
060: import org.openide.util.Exceptions;
061:
062: /**
063: * This file is originally from Retouche, the Java Support
064: * infrastructure in NetBeans. I have modified the file as little
065: * as possible to make merging Retouche fixes back as simple as
066: * possible.
067: *
068: * The ClassIndex provides access to information stored in the
069: * persistent index. It can be used to obtain list of packages
070: * or declared types. It can be also used to obtain a list of
071: * source files referencing given type (usages of given type).
072: *
073: * @author Petr Hrebejk, Tomas Zezula
074: * @author Tor Norbye
075: */
076: public final class ClassIndex extends Index {
077:
078: private static final Logger LOGGER = Logger
079: .getLogger(ClassIndex.class.getName());
080:
081: private final Language language;
082: private final ClassPath bootPath;
083: private final ClassPath classPath;
084: private final ClassPath sourcePath;
085:
086: private Set<ClassIndexImpl> sourceIndeces; // XXX Indices
087: private Set<ClassIndexImpl> depsIndeces;
088:
089: // Constants moved up to Index
090:
091: static {
092: ClassIndexImpl.FACTORY = new ClassIndexFactoryImpl();
093: }
094:
095: ClassIndex(final Language language, final ClassPath bootPath,
096: final ClassPath classPath, final ClassPath sourcePath) {
097: this .language = language;
098: //assert bootPath != null;
099: //assert classPath != null;
100: //assert sourcePath != null;
101: this .bootPath = bootPath;
102: this .classPath = classPath;
103: this .sourcePath = sourcePath;
104: }
105:
106: public Language getLanguage() {
107: return language;
108: }
109:
110: public void search(final String primaryField, final String name,
111: final NameKind kind, final Set<SearchScope> scope, /*final ResultConvertor<T> convertor,*/
112: final Set<SearchResult> result, Set<String> terms)
113: throws IOException {
114: assert primaryField != null;
115: assert name != null;
116: assert kind != null;
117: final Iterable<? extends ClassIndexImpl> queries = this
118: .getQueries(scope);
119: for (ClassIndexImpl query : queries) {
120: query
121: .search(primaryField, name, kind, scope, result,
122: terms);
123: }
124: if (LOGGER.isLoggable(Level.FINE)) {
125: LOGGER.fine(String.format(
126: "ClassIndex.search returned %d elements\n", result
127: .size()));
128: }
129: }
130:
131: private static class ClassIndexFactoryImpl implements
132: ClassIndexFactory {
133:
134: public ClassIndex create(final Language language,
135: final ClassPath bootPath, final ClassPath classPath,
136: final ClassPath sourcePath) {
137: return new ClassIndex(language, bootPath, classPath,
138: sourcePath);
139: }
140:
141: }
142:
143: private synchronized Iterable<? extends ClassIndexImpl> getQueries(
144: final Set<SearchScope> scope) {
145: Set<ClassIndexImpl> result = new HashSet<ClassIndexImpl>();
146:
147: if (scope.contains(SearchScope.SOURCE)) {
148: if (this .sourceIndeces == null) {
149: Set<ClassIndexImpl> indeces = new HashSet<ClassIndexImpl>();
150: createQueriesForRoots(language, this .sourcePath, true,
151: indeces);
152: this .sourceIndeces = indeces;
153: }
154: result.addAll(this .sourceIndeces);
155: }
156:
157: if (scope.contains(SearchScope.DEPENDENCIES)) {
158: if (this .depsIndeces == null) {
159: Set<ClassIndexImpl> indeces = new HashSet<ClassIndexImpl>();
160: // BEGIN TOR MODIFICATIONS
161: List<ClassPath.Entry> entries = this .classPath
162: .entries();
163: if (entries.size() == 0) {
164: // For files outside of my projects (such as the libraries in the ruby
165: // installation) I don't get a classpath, so I end up with a fallback
166: // boot ClassPath containing Java .jar files. I don't want that - I want
167: // the boot indices from the Ruby libraries instead. I need to look
168: // into the ClassPath platform to support to fix it there, but that's
169: // too late/risky for now; so work around this instead. When we have an
170: // empty classpath, use the boot indices instead.
171: Set<ClassIndexImpl> bootIndices = ClassIndexManager
172: .get(language).getBootIndices();
173: indeces.addAll(bootIndices);
174: } else {
175: createQueriesForRoots(language, this .bootPath,
176: false, indeces);
177: }
178: // END TOR MODIFICATIONS
179: createQueriesForRoots(language, this .classPath, false,
180: indeces);
181: this .depsIndeces = indeces;
182: }
183: result.addAll(this .depsIndeces);
184: }
185: if (LOGGER.isLoggable(Level.FINE)) {
186: LOGGER
187: .fine(String
188: .format(
189: "ClassIndex.queries[Scope=%s, sourcePath=%s, bootPath=%s, classPath=%s] => %s\n",
190: scope, sourcePath, bootPath,
191: classPath, result));
192: }
193: return result;
194: }
195:
196: // Public for the lucene browser
197: public static/*private*/void createQueriesForRoots(
198: final Language language, final ClassPath cp,
199: final boolean sources,
200: final Set<? super ClassIndexImpl> queries) {
201: final GlobalSourcePath gsp = GlobalSourcePath.getDefault();
202: List<ClassPath.Entry> entries = cp.entries();
203: for (ClassPath.Entry entry : entries) {
204: try {
205: URL[] srcRoots;
206: if (!sources) {
207: URL srcRoot = org.netbeans.modules.gsfret.source.usages.Index
208: .getSourceRootForClassFolder(language,
209: entry.getURL());
210: if (srcRoot != null) {
211: srcRoots = new URL[] { srcRoot };
212: } else {
213: srcRoots = gsp.getSourceRootForBinaryRoot(entry
214: .getURL(), cp, true);
215: if (srcRoots == null) {
216: srcRoots = new URL[] { entry.getURL() };
217: }
218: }
219: //End to be removed
220: } else {
221: srcRoots = new URL[] { entry.getURL() };
222: }
223: for (URL srcRoot : srcRoots) {
224: ClassIndexImpl ci = ClassIndexManager.get(language)
225: .getUsagesQuery(srcRoot);
226: if (ci != null) {
227: queries.add(ci);
228: }
229: }
230: } catch (IOException ioe) {
231: Exceptions.printStackTrace(ioe);
232: }
233: }
234: }
235: }
|