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-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.editor.java;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.event.DocumentEvent;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.queries.JavadocForBinaryQuery;
import org.netbeans.api.java.queries.SourceForBinaryQuery;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.WeakEventListenerList;
import org.netbeans.editor.ext.java.JavaSyntaxSupport;
import org.netbeans.editor.ext.java.JavaCompletion;
import org.netbeans.editor.ext.java.JCClass;
import org.netbeans.editor.ext.java.JCType;
import org.netbeans.editor.ext.java.JCFinder;
import org.netbeans.editor.ext.java.JCField;
import org.netbeans.editor.ext.java.JCParameter;
import org.netbeans.editor.ext.java.JCPackage;
import org.netbeans.editor.ext.java.JCMethod;
import org.netbeans.editor.ext.java.JCConstructor;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.ErrorManager;
import org.openide.src.SourceElement;
import org.openide.src.ClassElement;
import org.openide.src.Identifier;
import org.openide.src.FieldElement;
import org.openide.src.Element;
import org.openide.src.MemberElement;
import org.openide.src.InitializerElement;
import org.openide.src.MethodElement;
import org.openide.src.ConstructorElement;
import org.openide.src.Type;
import org.openide.cookies.SourceCookie;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.OpenCookie;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.nodes.Node;
import org.openide.filesystems.*;


/**
* Support methods for syntax analyzes
*
* @author Miloslav Metelka
* @version 1.00
*/

public class NbJavaSyntaxSupport extends JavaSyntaxSupport {

    protected static final String PACKAGE_SUMMARY = "package-summary"; // NOI18N
    
    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];

    private HashMap jcLookupCache = new HashMap(307);

    protected boolean jcValid;
    
    private ParsingListener parsingListener;
    
    private static boolean parsingListenerInitialized;

    /** Support for firing change events */
    private static final WeakEventListenerList listenerList = new WeakEventListenerList();
    
    public NbJavaSyntaxSupport(BaseDocument doc) {
        super(doc);
        
        initParsingListener();

        if (parsingListener == null) {
            parsingListener = new ParsingListenerImpl();
            addParsingListener(parsingListener);
        }
    }
    
    
    protected JCFinder getFinder() {
        DataObject dobj = NbEditorUtilities.getDataObject(getDocument());
        assert dobj != null;
        FileObject fo = dobj.getPrimaryFile();
        return JCFinderFactory.getDefault().getFinder(fo);
    }

    /** Add weak listener to listen to java module parsing events */
    private static synchronized void addParsingListener(ParsingListener l) {
        listenerList.add(ParsingListener.class, l);
    }

    /** Remove listener from java module parsing events */
    private static synchronized void removeParsingListener(ParsingListener l) {
        listenerList.remove(ParsingListener.class, l);
    }

    private static synchronized void fireParsingEvent(ParsingEvent evt) {
        ParsingListener[] listeners = (ParsingListener[])
             listenerList.getListeners(ParsingListener.class);

        for (int i = 0; i < listeners.length; i++) {
            listeners[i].objectParsed(evt);
        }
    }
    
    protected void documentModified(DocumentEvent evt) {
        super.documentModified(evt);
        jcValid = false;
    }

    protected int getMethodStartPosition(int pos) {
        DataObject dob = NbEditorUtilities.getDataObject(getDocument());
        if (dob != null) {
            try {
                SourceCookie.Editor sce = (SourceCookie.Editor)dob.getCookie(SourceCookie.Editor.class);
                if (sce != null) {
                    Element elem = sce.findElement(pos);
                    if (elem != null) {
                        javax.swing.text.Element swingElem = sce.sourceToText(elem);
                        if (swingElem != null) {
                            return swingElem.getStartOffset();
                        }
                    }
                }
            } catch (NullPointerException e) { // due to some bug in parser !!! [PENDING]
            }
        }

        return 0;
    }

    /** Returns true if className is in import, but in a package, that hasn't updated DB */
    protected boolean isUnknownImport(String className){
        // check for directly imported class
        boolean ret = super.isUnknownImport(className);
        if (ret) return ret;
        
        return ret;

// XXX:
// I'm not sure about exact meaning of the code below.
// Mato explained that it is bugfix for #18078 and may be obsolete.
//
// Anyway, if it is needed the classpath of the project to which the document
// being edited belongs can be searched for.
//
//        // check for class in all unknown imported packages
//        List unknownImports = getUnknownImports();
//        for(int i=0; i2) { //NOI18N
//                imp = imp.substring(0,imp.length()-2); //NOI18N
//            }else{
//                continue;
//            }
//            JCClass exactCls = getFinder().getExactClass(imp+"."+className); //NOI18N
//            // if class is mounted in FS and is not in parser DB return true
//            if ( isMounted(imp,className) && exactCls==null ) return true;
//        }
//        
//        return ret;
    }
    
    public int findGlobalDeclarationPosition(String varName, int varPos) {
        Element e = getElementAtPos(varPos);
        if (e instanceof MemberElement) {
            MemberElement me = (MemberElement)e;
            while (me != null) {
                if (me instanceof ClassElement) {
                    ClassElement ce = (ClassElement)me;
                    FieldElement[] fields = ce.getFields();
                    if (fields != null) {
                        for (int i = 0; i < fields.length; i++) {
                            if (fields[i].getName().getFullName().equals(varName)) {
                                DataObject dob = NbEditorUtilities.getDataObject(getDocument());
                                if (dob != null) {
                                    SourceCookie.Editor sce = (SourceCookie.Editor)dob.getCookie(SourceCookie.Editor.class);
                                    if (sce != null) {
                                        javax.swing.text.Element elem = sce.sourceToText(fields[i]);
                                        if (elem != null) {
                                            return elem.getStartOffset();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                me = me.getDeclaringClass();
            }
        }
        return -1;
    }

    private Element getElementAtPos(int pos) {
        DataObject dob = NbEditorUtilities.getDataObject(getDocument());
        if (dob != null) {
            SourceCookie.Editor sce = (SourceCookie.Editor)dob.getCookie(SourceCookie.Editor.class);
            if (sce != null) {
                return sce.findElement(pos);
            }
        }
        return null;
    }

    /** Get the class element(s) according to the current position */
    protected ClassElement getClassElement(int pos) {
        ClassElement ce = null;
        Element elem = getElementAtPos(pos);
        if (elem instanceof ClassElement) {
            ce = (ClassElement)elem;
        } else if (elem instanceof MemberElement) {
            ce = ((MemberElement)elem).getDeclaringClass();
        } else if (elem instanceof InitializerElement) {
            ce = ((InitializerElement)elem).getDeclaringClass();
        }
        return ce;
    }

    /** Returns the JCClass of the top class */
    public JCClass getTopClass(){
        DataObject dob = NbEditorUtilities.getDataObject(getDocument());
        if (dob != null) { // Fix of #25154
            ClassPath cp = ClassPath.getClassPath(dob.getPrimaryFile(), ClassPath.SOURCE);
            if (cp != null) {
                String topClassName = cp.getResourceName(dob.getPrimaryFile(), '.', false);
                assert topClassName != null;
                return getFinder().getExactClass(topClassName);
            }
        }
        return null;
    }
    
    public JCClass getClassFromName(String className, boolean searchByName) {
        // look for the inner classes first
        JCClass innerCls = JCExtension.findResultInnerClass(getFinder(), getTopClass(), className, this.getDocument());
        return (innerCls != null) ? innerCls : super.getClassFromName(className, searchByName);
    }    
    
    /** Returns the package name of this source */
    public String getPackage(){
        DataObject dob = NbEditorUtilities.getDataObject(getDocument());
        if (dob != null) {
            SourceCookie sc = (SourceCookie)dob.getCookie(SourceCookie.class);
            if (sc != null) {
                SourceElement se = sc.getSource();
                if (se != null) {
                    Identifier pkg = se.getPackage();
                    if (pkg!=null){
                        return pkg.getFullName();
                    }
                }
            }
        }
        return ""; //NOI18N
    }
    
    public JCClass getClass(int pos) {
        ClassElement ce = getClassElement(pos);
        if (ce != null) {
            return getFinder().getExactClass(ce.getName().getFullName());
        }
        return null;
    }

    public boolean isStaticBlock(int pos) {
        Element elem = getElementAtPos(pos);
        if (elem instanceof MethodElement) {
            return (((MethodElement)elem).getModifiers() & Modifier.STATIC) != 0;
        } else if (elem instanceof FieldElement) {
            return (((FieldElement)elem).getModifiers() & Modifier.STATIC) != 0;
        } else if (elem instanceof InitializerElement) {
            return true;
        }
        return false;
    }

    private ClassElement[] getAllClassElements() {
        DataObject dob = NbEditorUtilities.getDataObject(getDocument());
        if (dob != null) {
            SourceCookie sc = (SourceCookie)dob.getCookie(SourceCookie.class);
            if (sc != null) {
                SourceElement se = sc.getSource();
                if (se != null) {
                    return se.getAllClasses();
                }
            }
        }
        return null;
    }
    
    /** Check if sources for code completion are already available */
    public boolean isPrepared(){
        DataObject dob = NbEditorUtilities.getDataObject(getDocument());
        if (dob != null) {
            SourceCookie sc = (SourceCookie)dob.getCookie(SourceCookie.class);
            if (sc != null) {
                SourceElement se = sc.getSource();
                if (se != null) {
                    if ( (se.getStatus() == SourceElement.STATUS_NOT) ||
                         (se.getStatus() == SourceElement.STATUS_ERROR) ){
                        return false;
                    }
                }
            }
        }
        return true;
    }


    protected Map buildGlobalVariableMap(int pos) {
        refreshClassInfo();
        JCFinder finder = getFinder();
        JCClass cls = getClass(pos);
        if (cls != null) {
            HashMap varMap = new HashMap();
            List fldList = finder.findFields(cls, "", false, false, true); // NOI18N
            for (int i = fldList.size() - 1; i >= 0; i--) {
                JCField fld = (JCField)fldList.get(i);
                varMap.put(fld.getName(), fld.getType());
            }
            return varMap;
        }
        return null;
    }

    protected ClassElement recurseClasses(ClassElement[] classes, String name) {
        for (int i = 0; i < classes.length; i++) {
            ClassElement ce = classes[i];
            if (ce.getName().getFullName().replace('$', '.').equals(name)) {
                return ce;
            }
            ClassElement inner = recurseClasses(ce.getClasses(), name);
            if (inner != null) {
                return inner;
            }
        }
        return null;
    }

    protected DataObject getDataObject(FileObject fo) {
        DataObject dob = null;
        if (fo != null) {
            try {
                dob = DataObject.find(fo);
            } catch (DataObjectNotFoundException e) {
            }
        }
        return dob;
    }

    private DataObject getDataObject(JCClass cls) {
        String name = cls.getFullName().replace('.', '/');
        FileObject fo = findResource(name+".java"); // NOI18N
        if (fo != null) {
            return getDataObject(fo);
        }
        return null;
    }

    protected SourceElement getSourceElement(DataObject classDOB) {
        SourceElement se = null;
        if (classDOB != null) {
            SourceCookie sc = (SourceCookie)classDOB.getCookie(SourceCookie.class);
            if (sc != null) {
                se = sc.getSource();
            }
        }
        return se;
    }

    private ClassElement getClassElement(DataObject classDOB, JCClass cls) {
        SourceElement se = getSourceElement(classDOB);
        ClassElement ce = null;
        if (se != null) {
            ce = recurseClasses(se.getClasses(), cls.getFullName());
        }
        return ce;
    }

    protected void openAtElement(final DataObject classDOB, final Element e) {
        new Thread() {
            public void run() {
                OpenCookie oc = (e != null)
                                ? (OpenCookie)e.getCookie(OpenCookie.class)
                                : (OpenCookie)classDOB.getCookie(OpenCookie.class);
                if (oc != null) {
                    oc.open();
                    return;
                }
            }
        }.start();
    }

    private String getSourceName(JCClass cls, boolean shortName) {
        String name = cls.getName();
        int icInd = name.indexOf('.');
        if (icInd >= 0) { // inner class name
            name = name.substring(0, icInd);
        }
        return shortName ? name : cls.getPackageName() + '.' + name;
    }

    /** Open the source according to the given object.
    * @param item completion object that is decoded and the appropriate
    *   source is opened.
    * @param findDeclaration find the declaration behaior that is different
    *   for the fields - it opens the source of the type of the field.
    * @param simulate simulate the opening but don't open in reality.
    * @return for simulate mode return the short display name (without package name)
    *   of the item or null if the item is not recognized.
    *   For non-simulate mode return the null if the item was successfully opened
    *   or the display name if the item's object can't be found.
    */
    public String openSource(Object item, boolean findDeclaration, boolean simulate) {
        DataObject dob = null;
        Element elem = null;
        String ret = null;
        boolean found = false;

        if (item instanceof JCPackage) {
            if (!findDeclaration) {
                String pkgName = ((JCPackage)item).getName();
                
                if ( (pkgName==null) || (pkgName.length() <= 0) ) return null;
                
                FileObject fo = findResource(pkgName.replace('.', '/'));
                if (fo != null) {
                    dob = getDataObject(fo);
                    if (dob != null) {
                        Node node = dob.getNodeDelegate();
                        if (node != null) {
                            found = true;
                            if (!simulate) {
                                org.openide.nodes.NodeOperation.getDefault().explore(node); // explore the package
                            }
                        }
                        dob = null; // don't try to open dob
                    }
                }
                if (simulate || !found) {
                    ret = pkgName;
                }

            }
        } else if (item instanceof JCClass) {
            JCClass cls = (JCClass)item;
            if (!JavaCompletion.isPrimitiveClass(cls)) {
                dob = getDataObject(cls);

                if (dob != null) {
                    found = true;
                    elem = getClassElement(dob, cls);
                }
                if (simulate || !found) {
                    ret = getSourceName(cls, simulate);
                }
            }

        } else if (item instanceof JCField) {
            JCField fld = (JCField)item;
            JCClass cls = findDeclaration ? fld.getClazz() : fld.getType().getClazz();
            if (!JavaCompletion.isPrimitiveClass(cls)) {
                dob = getDataObject(cls);
                
                if (dob != null) {
                    found = true;
                    ClassElement ce = getClassElement(dob, cls);
                    if (ce != null) {
                        elem = JCExtension.findFieldElement(fld, ce);
                    }
                }
                if (simulate || !found) {
                    ret = getSourceName(cls, simulate);
                }
            }

        } else if (item instanceof JCMethod) {
            JCMethod mtd = (JCMethod)item;
            JCClass cls = mtd.getClazz();
            if (!JavaCompletion.isPrimitiveClass(cls)) {
                dob = getDataObject(cls);
                
                if (dob != null) {
                    found = true;
                    ClassElement ce = getClassElement(dob, cls);
                    if (ce != null) {
                        elem = JCExtension.findMethodElement(mtd, ce);
                    }
                }
                if (simulate || !found) {
                    ret = getSourceName(cls, simulate);
                }
            }

        } else if (item instanceof JCConstructor) {
            JCConstructor ctr = (JCConstructor)item;
            JCClass cls = ctr.getClazz();
            if (!JavaCompletion.isPrimitiveClass(cls)) {
                dob = getDataObject(cls);
                
                if (dob != null) {
                    found = true;
                    ClassElement ce = getClassElement(dob, cls);
                    if (ce != null) {
                        elem = JCExtension.findConstructorElement(ctr, ce);
                    }
                }
                
                if (simulate || !found) {
                    ret = getSourceName(cls, simulate);
                }
            }
        }

        // Add the current (probably opened) componetn to jump-list
        if (dob != null) {
            if (!simulate) {
                openAtElement(dob, elem);
                NbEditorUtilities.addJumpListEntry(dob);
            }
        }
        return ret;
    }

    
    protected URL getDocFileObjects(String fqName, String javadocFilename) {
        DataObject dobj = NbEditorUtilities.getDataObject(getDocument());
        if (dobj == null) return null;
        FileObject fo = dobj.getPrimaryFile();
        
        String search = fqName.replace('.', '/');
        if (javadocFilename == null) {
            search += ".class"; // NOI18N
        }
        
        // try to find class/package on classpath of the file being editted
        FileObject cpfo = null;
        ClassPath cp = ClassPath.getClassPath(fo, ClassPath.COMPILE);
        if (cp != null) {
            cpfo = cp.findResource(search);
        }
        if (cpfo == null) {
            cp = ClassPath.getClassPath(fo, ClassPath.BOOT);
            if (cp != null) {
                cpfo = cp.findResource(search);
            }
        }
        if (cpfo == null) {
            // nothing was found
            return null;
        }
        
        // convert fileobject to URL
        FileObject ownerRoot = cp.findOwnerRoot(cpfo);
        if (ownerRoot == null) return null;
        URL url = URLMapper.findURL(ownerRoot, URLMapper.EXTERNAL);
        
        // now ask the Javadoc query to get Javadoc for the object
        search = fqName.replace('.', '/');
        if (javadocFilename != null) {
            search += "/" + javadocFilename; // NOI18N
        }
        search += ".html"; // NOI18N
        
        URL urls[] = JavadocForBinaryQuery.findJavadoc(url).getRoots();
        return findResource(search, urls);
    }
    
    private URL findResource(String resource, URL urls[]) {
        for (int i=0; i 0) {
                ClassPath sources = ClassPathSupport.createClassPath (sroots);
                FileObject fo2 = sources.findResource (resourceName);
                if (fo2 != null) {
                    return fo2;
                }
            }
        }
        return cp.findResource(resourceName);
    }
    
    class ParsingListenerImpl implements ParsingListener {
        
        public ParsingListenerImpl(){
        }
        
        public void objectParsed(ParsingEvent evt){
            if (evt==null) {
                return;
            }
            DataObject dob = NbEditorUtilities.getDataObject(getDocument());
            if (dob != null && dob == evt.getDataObject()) {
                SourceElement se = evt.getSourceElement();
                if (se==null) {
                    return;
                }
                
                SourceCookie sc = (SourceCookie)dob.getCookie(SourceCookie.class);
                if (sc != null) {
                    SourceElement seLocal = sc.getSource();
                    if (seLocal != null && seLocal.equals(se)) {
                        jcValid = false;
                    }
                }
            }
        }
    }

    /** Attach listener on java source hierarchy parser */
    private static synchronized void initParsingListener(){
        if (parsingListenerInitialized == false){
            try {
                final ClassLoader loader = (ClassLoader)org.openide.util.Lookup.getDefault().lookup(ClassLoader.class);
                Class parsingClass = Class.forName(
                    "org.netbeans.modules.java.Parsing", false, loader); //NOI18N
                Class listenerClass = Class.forName(
                    "org.netbeans.modules.java.Parsing$Listener", false, loader); //NOI18N
                InvocationHandler ih =  new InvocationHandler(){
                        public Object invoke(Object proxy, Method method, Object[] args) {
                            if (args!=null && args[0]!=null){
                                try{
                                    Class parsingEventClass = args[0].getClass();
                                    Method getJavaDataObjectMethod = parsingEventClass.getMethod(
                                        "getJavaDataObject", EMPTY_CLASS_ARRAY); //NOI18N

                                    DataObject dob = (DataObject)getJavaDataObjectMethod.invoke(
                                        args[0], EMPTY_OBJECT_ARRAY);

                                    if (dob != null) {
                                        // getSourceElement() costly in refactoring
                                        // so should be done only if dataObject matches
                                        // Not checking se.getStatus()==SourceElement.STATUS_OK){
                                        // as it's always STATUS_OK anyway in refactoring builds
                                        fireParsingEvent(new ParsingEvent(dob));
                                    }
                                } catch (Throwable t) {
                                    org.netbeans.editor.Utilities.annotateLoggable(t);
                                }

                            }
                            return null;
                        }
                    };
                Object proxyListener = java.lang.reflect.Proxy.newProxyInstance(loader, 
                    new Class[] { listenerClass }, ih);
                Method addParsingListener = parsingClass.getMethod(
                    "addParsingListener",new Class[]{listenerClass});//NOI18N
                addParsingListener.invoke(parsingClass, new Object[]{proxyListener});
                parsingListenerInitialized = true;
            } catch (Throwable t) {
                org.netbeans.editor.Utilities.annotateLoggable(t);
            }
        }        
    }
    
    /** The event class used in Listener. */
    static class ParsingEvent extends java.util.EventObject {
        
        ParsingEvent(DataObject dob) {
            super(dob);
        }
        
        public DataObject getDataObject() {
            return (DataObject)getSource();
        }

        /** @return the source element which was parsed. */
        public SourceElement getSourceElement() {
            SourceCookie sc = (SourceCookie)getDataObject().getCookie(SourceCookie.class);
            return (sc != null) ? sc.getSource() : null;
        }

    }
    
    /** The listener interface for everybody who want to control all
    * parsed JavaDataObjects.
    */
    static interface ParsingListener extends java.util.EventListener {
        /** Method which is called everytime when some object is parsed.
        * @param evt The event with the details.
        */
        public void objectParsed(ParsingEvent evt);
    }
    
}
... 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.