alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.java;

import java.util.*;

import org.openide.cookies.SourceCookie;

import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;

import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;

import org.openide.src.*;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;

/**
 * This class implements Finder interface from org.openide.src and is used
 * to look up ClassElement relevant for the given name. The function is as follows:
 * The finder locates the first .java or .class file in the Repository, looking
 * at filesystems with capability COMPILE. If .java file (source) is found,
 * it is parsed and scanned for the element. The results are then returned.
 * 

* If .class is located first, the scan continues and the finder queries all * matching .java files whether they know about the .class that was found first. * They might, because of cross-directory compilation. *

* If one of the .java sources claims ownership over the .class, the ClassElement * is dug out of the source file, otherwise the finder returns null * and leaves the work to other finders. * * @author Svatopluk Dedic * @version 0.1 */ class ClassElementFinder implements ClassElement.Finder { /** * Enables tons of debug messages for tracing bugs and weird results. */ private static final boolean DEBUG = false; private static ClassElementFinder finder; /** * Hidden to prevent construction from outside. */ private ClassElementFinder() { } /** * Returns, creating it if necessary, an instance of Finder. The finder * is implemented as a singleton. */ public static ClassElementFinder getInstance() { if (finder != null) return finder; synchronized (ClassElementFinder.class) { if (finder == null) finder = new ClassElementFinder(); } return finder; } /** * @param fullName name as passed to ClassElement.forName. Must contain $ * as inner class delimiters. * @param packageDelimiter basically position of the last . in the fullName, * or 0 if there is none. * @param innerDelimiter index of the first $ in the fullName. Must be > * packageDelimiter. */ private ClassElement findSpecifiedInner(FileObject projectArtefact, String fullName, int packageDelimiter, int innerDelimiter) { String packName = packageDelimiter >= 0 ? fullName.substring(0, packageDelimiter) : ""; int classnameOffset = packageDelimiter + 1; String topName = fullName.substring(classnameOffset, innerDelimiter); FileObject fo = searchFile(projectArtefact, packName, topName); if (fo == null) return null; StringTokenizer tt = new StringTokenizer(fullName.substring(classnameOffset), "$"); // NOI18N return findClassInFile(fo, tt); } /** * Finds the specified ClassElement within the source, travesing through inner * classes. The Enumeration should contain Strings - beginning with the name * of the top-level class, followed by names of inner classes up to the one * the caller wants to locate. */ private ClassElement findInSource(SourceElement s, Enumeration names) { Identifier classID; ClassElement c; classID = Identifier.create((String)names.nextElement()); c = s.getClass(classID); if (DEBUG) { System.err.println("getClass(" + classID.getName() + ") = " + // NOI18N (c == null ? "nothing" : c.getName().getFullName())); // NOI18N } if (!names.hasMoreElements() || c == null) return c; do { classID = Identifier.create((String)names.nextElement()); c = c.getClass(classID); if (DEBUG) { System.err.println("getClass(" + classID.getName() + ") = " + // NOI18N (c == null ? "nothing" : c.getName().getFullName())); // NOI18N } } while (c != null && names.hasMoreElements()); return c; } /** * Tries to find ClassElement with the corresponding name. */ public ClassElement find(String className, FileObject projectArtefact) { int lastDot = className.length() - 1; int innerDelimiter = -1; ClassElement result; if (lastDot < 0) return null; while (lastDot > 0 && className.charAt(lastDot) != '.') { if (className.charAt(lastDot) == '$') innerDelimiter = lastDot; lastDot--; } if (lastDot == 0) { if (className.charAt(lastDot) == '.') { return null; //Invalid name } else { lastDot-=1; } } if (DEBUG) { System.err.println("[ClassFinder] Searching for " + className + // NOI18N " lastDot = " + lastDot + " delimiter = " + innerDelimiter); // NOI18N } // innerDelimiter > -1 --> specified an inner class. // we can find source with package className[0..lastDot - 1], // name className[lastDot + 1..innerDelimiter - 1] if (innerDelimiter > 0) return findSpecifiedInner(projectArtefact, className, lastDot, innerDelimiter); int nameEnd = className.length(); String baseName; String packName; FileObject f; if (lastDot > 0) { baseName = className.substring(lastDot + 1, nameEnd); packName = className.substring(0, lastDot); } else { baseName = className; packName = ""; // NOI18N } while (true) { FileObject fo = searchFile(projectArtefact, packName, baseName); if (fo != null) { if (DEBUG) { System.err.println("Finally found file " + f); // NOI18N } String partName = lastDot > 0? className.substring(lastDot + 1): className; result = findClassInFile(fo,new StringTokenizer(partName, ".")); // NOI18N if (result != null) return result; } // dive out from the package: if (lastDot <= 0) break; nameEnd = lastDot; lastDot = className.lastIndexOf('.', lastDot - 1); if (lastDot > 0) { baseName = className.substring(lastDot + 1, nameEnd); packName = className.substring(0, lastDot); } else { packName = ""; // NOI18N baseName = className.substring(0, nameEnd); } } return null; } /** * Attempts to locate the named class within the file. The enumeration * should produce String components of the class name, beginning with * top-level class name, followed by inner class name(s), if applicable. */ private ClassElement findClassInFile(FileObject f, Enumeration names) { DataObject d; SourceElement s; try { d = DataObject.find(f); SourceCookie sc = (SourceCookie)d.getCookie(SourceCookie.class); if (DEBUG) System.err.println("SourceCookie = " + sc); // NOI18N if (sc == null) return null; s = sc.getSource(); } catch (DataObjectNotFoundException ex) { return null; } return findInSource(s, names); } /** * Tries to find the designated class. It searches FileSystems in the * order defined by the Repository. If it finds a .class file, it * does not give up immediately, but tries to locate a matching .java * file * @param packName name of the package (folder) to look in. */ private FileObject searchFile(FileObject projectArtefact, String packName, String baseName) { StringBuffer sb = new StringBuffer(packName.replace('.', '/')); if (packName.length() != 0) sb.append('/'); sb.append(baseName); String resNameBase = sb.toString(); FileObject result = null; ClassPath classPath = ClassPath.getClassPath(projectArtefact,ClassPath.SOURCE); if (classPath != null) { result = classPath.findResource(resNameBase+".java"); // NOI18N if (result != null) { return result; } } classPath = ClassPath.getClassPath (projectArtefact,ClassPath.COMPILE); if (classPath != null) { result = classPath.findResource(resNameBase+".class"); // NOI18N if (result != null) { //Try to find source for it ClassPath.Entry root = findRoot (classPath, result); FileObject[] sources = findSourceFile (root, resNameBase); if (sources.length == 1) { //And return it only if it is safe return sources[0]; } return result; } else { // the COMPILE classpath items might not be built yet and // so check the sources directly: Iterator it = classPath.entries().iterator(); while (it.hasNext()) { ClassPath.Entry entry = (ClassPath.Entry)it.next(); FileObject[] sourceRoots = SourceForBinaryQuery.findSourceRoots(entry.getURL()).getRoots(); if (sourceRoots.length > 0) { ClassPath cp = ClassPathSupport.createClassPath(sourceRoots); result = cp.findResource(resNameBase+".java"); // NOI18N if (result != null) { return result; } } } } } classPath = ClassPath.getClassPath (projectArtefact,ClassPath.BOOT); if (classPath != null) { result = classPath.findResource(resNameBase+".class"); // NOI18N if (result != null) { //Try to find source for it ClassPath.Entry root = findRoot (classPath, result); FileObject[] sources = findSourceFile (root, resNameBase); if (sources.length == 1) { //And return it only if it is safe return sources[0]; } return result; } } return null; } public ClassElement find(Class clazz, FileObject context) { return null; } /** * Returns the source file for given class file. * @param root the ClassPath root containing the compiled file * @param resourceName the resource name e.g. org/netbeans/modules/java/JavaDataObject.class * @return FileObject or null */ private static FileObject[] findSourceFile (ClassPath.Entry root, String resourceName) { Set result = new HashSet (); if (resourceName != null) { resourceName+=".java"; //NOI18N FileObject[] sourceRoots = SourceForBinaryQuery.findSourceRoots (root.getURL()).getRoots(); if (sourceRoots.length > 0) { ClassPath cp = ClassPathSupport.createClassPath (sourceRoots); result.addAll(cp.findAllResources (resourceName)); } } return (FileObject[]) result.toArray (new FileObject [result.size()]); } private static ClassPath.Entry findRoot (ClassPath cp, FileObject file) { FileObject owner = cp.findOwnerRoot (file); for (Iterator it = cp.entries().iterator(); it.hasNext();) { ClassPath.Entry entry = ((ClassPath.Entry)it.next()); FileObject root = entry.getRoot(); if (root != null && root.equals(owner)) return entry; } return null; } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.