All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.javadoc.search.SrcFinder Maven / Gradle / Ivy

There is a newer version: RELEASE240
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.modules.javadoc.search;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.Trees;
import java.io.IOException;
import java.net.URL;
import java.util.StringTokenizer;
import java.util.ArrayList;
import java.util.Set;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import org.netbeans.api.java.classpath.GlobalPathRegistry;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.JavadocForBinaryQuery;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.TreeUtilities;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;


/** This class finds the source to show it instead of documentation.
 *
 */
public final class SrcFinder extends Object {

    /** SrcFinder is a singleton */
    private  SrcFinder() {
    }

    static Object[]/*FileObject, ElementHandle*/ findSource(String aPackage, URL url) {

        aPackage = aPackage.replace( '.', '/' ); // NOI18N
        String thePackage = null;
        final String member = url.getRef(); 
        String clazz = url.getFile();
        String filename = null;

        int pIndex;
        
        if ((pIndex = clazz.toLowerCase().lastIndexOf(aPackage.trim().toLowerCase())) != -1) {
            thePackage = clazz.substring(pIndex, pIndex + aPackage.trim().length()  - 1 );
            clazz = clazz.substring( pIndex + aPackage.trim().length(), clazz.length() - 5 );

            int ei;
            if ( ( ei = clazz.indexOf('.')) != -1 ) {
                filename = clazz.substring(0, ei );
            }
            else
                filename = clazz;

        }
        
//        System.out.println("================================");
//        System.out.println("URL     :" + url   );
//        System.out.println("aPCKG   :" + aPackage );
//        System.out.println("--------------------------------");
//        System.out.println("MEMBER  :" + member ); // NOI18N
//        System.out.println("CLASS   :" + clazz ); // NOI18N
//        System.out.println("PACKAGE :" + thePackage ); // NOI18N
//        System.out.println("FILENAME:" + filename ); // NOI18N

        String resourceName = thePackage + "/" + filename + ".java"; // NOI18N
        FileObject fo = searchResource(url, resourceName);
        
        final ElementHandle[] handles = new ElementHandle[1];
        
        if ( fo != null ) {
            final String className = clazz;
            JavaSource js = JavaSource.forFileObject(fo);
            
            try {
                js.runUserActionTask(new CancellableTask() {

                    public void cancel() {
                    }

                    public void run(CompilationController ctrl) throws Exception {
                        ctrl.toPhase(Phase.ELEMENTS_RESOLVED);
                        TypeElement classElm = findClass(ctrl, className);
                        if (classElm == null) {
                            // bad luck
                        } else if (member == null) {
                            handles[0] = ElementHandle.create(classElm);
                        } else {
                            int pi = member.indexOf('(');
                            if (pi == -1) {
                                // we are looking for fields
                                handles[0] = findField(classElm, member);
                            } else {
                                // We are looking for method or constructor
                                handles[0] = findMethod(ctrl, classElm, member );
                            }
                        }
                    }
                }, true);
            } catch (IOException ex) {
                Logger.getLogger(SrcFinder.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage(), ex);
            }
            
        }
        return handles[0] != null? new Object[]{fo, handles[0]}: null;
    }

    /**
     * searches the file corresponding to javadoc url on all source path.
     * {@link GlobalPathRegistry#findResource}
     * is insufficient due to returning just the first occurrence of the file. So having
     * two platforms installed would bring troubles.
     * @param url javadoc
     * @param respath resource in form java/lang/Character.java
     * @return the file
     */ 
    private static FileObject searchResource(URL url, String respath) {
        FileObject res = searchBinaryPath(ClassPath.BOOT, respath, url);
        
        if (res == null) {
            res = searchBinaryPath(ClassPath.COMPILE, respath, url);
        }
        
        if (res == null) {
            res = searchSourcePath(respath, url);
        }
        
        return res;
        
    }

    private static FileObject searchBinaryPath(String classPathID, String respath, URL url) {
        Set cpaths = GlobalPathRegistry.getDefault().getPaths(classPathID);
        for (ClassPath cpath: cpaths) {
            FileObject[] cpRoots = cpath.getRoots();
            for (int i = 0; i < cpRoots.length; i++) {
                SourceForBinaryQuery.Result result = SourceForBinaryQuery.findSourceRoots(URLMapper.findURL(cpRoots[i], URLMapper.EXTERNAL));
                FileObject[] srcRoots = result.getRoots();
                for (int j = 0; j < srcRoots.length; j++) {
                    FileObject fo = srcRoots[j].getFileObject(respath);
                    if (fo != null && isJavadocAssigned(cpath, url)) {
                        return fo; 
                    }
                }
            }
        }
        return null;
    }

    private static FileObject searchSourcePath(String respath, URL url) {
        Set cpaths = GlobalPathRegistry.getDefault().getPaths(ClassPath.SOURCE);
        for (ClassPath cpath: cpaths) {
            FileObject fo = cpath.findResource(respath);
            if (fo != null && isJavadocAssigned(cpath, url)) {
                return fo;
            }
        }
        
        return null;
    }
    
    /**
     * checks if the javadoc url is assigned to a given classpath 
     * @param cpath classpath
     * @param url javadoc
     * @return is assigned?
     */ 
    private static boolean isJavadocAssigned(ClassPath cpath, URL url) {
        FileObject[] cpRoots = cpath.getRoots();
        String urlPath = url.toExternalForm();
        for (int i = 0; i < cpRoots.length; i++) {
            JavadocForBinaryQuery.Result result = JavadocForBinaryQuery.findJavadoc(URLMapper.findURL(cpRoots[i], URLMapper.EXTERNAL));
            URL[] jdRoots = result.getRoots();
            for (int j = 0; j < jdRoots.length; j++) {
                String jdRootPath = jdRoots[j].toExternalForm();
                if (urlPath.indexOf(jdRootPath) >= 0) {
                    return true;
                }
            }
        }
        return false;
    }
    
    private static TypeElement findClass(CompilationController ctrl, String className) {
        CompilationUnitTree cunit = ctrl.getCompilationUnit();
        for (Tree declTree : cunit.getTypeDecls()) {
            ClassTree classTree = (ClassTree) declTree;
            if (className.equals(classTree.getSimpleName().toString())) {
                Trees trees = ctrl.getTrees();
                TypeElement classElm = (TypeElement) trees.getElement(trees.getPath(cunit, classTree));
                return classElm;
            }
        }
        return null;
    }
    
    private static ElementHandle findField(TypeElement classElm, String name) {
        for (Element elm: classElm.getEnclosedElements()) {
            if (elm.getKind() == ElementKind.FIELD &&
                    name.equals(elm.getSimpleName().toString())) {
                return ElementHandle.create(elm);
            }
        }
        return null;
    }
    
    /** Gets the method we are looking for
     */
    private static ElementHandle findMethod(CompilationController ctrl, TypeElement ce, String member) {
        TreeUtilities utils = ctrl.getTreeUtilities();

        int pi = member.indexOf( '(' );
        String name = member.substring( 0, pi );

        StringTokenizer tokenizer = new StringTokenizer( member.substring( pi ), " ,()" ); // NOI18N
        List paramList = new ArrayList();

        while( tokenizer.hasMoreTokens() ) {
            String token = tokenizer.nextToken();
            if (token.endsWith("...")) { // NOI18N
                // translate varargs to array
                token = token.substring(0, token.length() - 3);
                token += "[]"; // NOI18N
            }
            TypeMirror type = utils.parseType(token, ce);
            paramList.add(type);
        }
        
        // search method or constructor
        for (Element e: ce.getEnclosedElements()) {
            if (e.getKind() == ElementKind.METHOD
                    && name.equals(e.getSimpleName().toString())
                    && compareTypes(ctrl, paramList, ((ExecutableElement) e).getParameters())) {
                return ElementHandle.create(e);
            } else if (e.getKind() == ElementKind.CONSTRUCTOR
                    && name.equals(ce.getSimpleName().toString())
                    && compareTypes(ctrl, paramList, ((ExecutableElement) e).getParameters())) {
                return ElementHandle.create(e);
            }
        }
        
        return null;
    }
    
    private static boolean compareTypes(CompilationController ctrl, List types, List params) {
        if (types.size() != params.size()) {
            return false;
        }
        
        Iterator itParams = params.iterator();
        Iterator itTypes = types.iterator();
        while (itParams.hasNext()) {
            VariableElement varEl = itParams.next();
            TypeMirror paramType = varEl.asType();
            TypeMirror type = itTypes.next();
            
            // check types are the same kind
            if (type.getKind() != paramType.getKind()) {
                return false;
            }
            
            // check elements since javadoc ignores generics
            if (type.getKind() == TypeKind.DECLARED) {
                Element paramElm = ((DeclaredType) paramType).asElement();
                Element typeElm = ((DeclaredType) type).asElement();
                if (paramElm != typeElm) {
                    return false;
                }
            } else if (!ctrl.getTypes().isSameType(type, paramType)) { // arrays, primitives
                return false;
            }
            
        }
        return true;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy