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

package org.netbeans.modules.javadoc.comments;

import java.text.MessageFormat;
import java.text.Format;
import javax.swing.*;
import javax.jmi.reflect.JmiException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;

import org.openide.src.JavaDoc;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.SourceCookie;
import org.openide.nodes.Node;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataFolder;
import org.openide.util.Utilities;
import org.openide.util.RequestProcessor;
import org.openide.ErrorManager;
import org.openide.src.JavaDocTag;
import org.openide.src.SourceException;
import org.openide.src.JavaDocSupport;
import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
import org.netbeans.modules.javacore.internalapi.JMIElementCookie;
import org.netbeans.modules.java.ui.nodes.SourceNodes;
import org.netbeans.jmi.javamodel.*;
import org.netbeans.api.mdr.events.MDRChangeListener;
import org.netbeans.api.mdr.events.MDRChangeEvent;
import org.netbeans.api.mdr.events.ExtentEvent;
import org.netbeans.api.mdr.MDRepository;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.util.*;
import java.util.List;
import java.awt.*;

/** Contains static methods for generating default JavaDoc comments for
 * java data object hierarchy elements.
 *
 * Checks for Comment errors in JavaNodes
 *
 * @author Petr Hrebejk
 */
public final class AutoCommenter extends Object implements JavaTagNames {

    public static final int JDC_OK = 1;
    public static final int JDC_MISSING = 2;
    public static final int JDC_ERROR = 4;
    
    private static final RequestProcessor QUEUE = new RequestProcessor("Auto CommenterQueue"); // NOI18N
    
    /** List of DataObjects. */
    private final ArrayList dataObjects;
    ArrayList elements;
    Node[] nodes;
    /** listens to all dataobjects elements*/
    private final WPCL dataObjectListener = new WPCL(this);

    /** Utility field holding the PropertyChangeListener. */
    private AutoCommentChangeListener autoCommentChangeListener =  null;

    /** Creates an empty AutoCommenter */
    AutoCommenter() {
        this( new Node[0] );
    }

    /** Creates Auto commenter for nodes */
    AutoCommenter ( Node[] nodes ) {
        dataObjects = new ArrayList();
        this.nodes = nodes;
    }
    
    private void updateDataObjects() {
        
        List newDOs = new LinkedList();
        
        for (int i = 0; i < nodes.length; i++) {
            DataFolder df = (DataFolder) nodes[i].getCookie(DataFolder.class);
            Object cookie = null;
            if(df != null && df.isValid()){
                DataObject[] children = df.getChildren();
                for (int n = 0; n < children.length; n++){
                    final DataObject child = children[n];
                    cookie = child.getCookie(JMIElementCookie.class);
                    if (cookie == null) {
                        cookie = child.getCookie(SourceCookie.class); 
                    }
                    if (cookie != null && child.getPrimaryFile().canWrite()){
                        if(!newDOs.contains(child)){
                            child.addPropertyChangeListener(dataObjectListener);
                            newDOs.add(child);
                        }
                    }
                }            
                continue;
            } else {
                cookie = nodes[i].getCookie(JMIElementCookie.class);
                if (cookie == null) {
                    cookie = nodes[i].getCookie(SourceCookie.class); 
                }
            }
            final DataObject doj = (DataObject) nodes[i].getCookie(DataObject.class);
            if ( cookie == null || doj == null || !doj.getPrimaryFile().canWrite() )
                continue;            
            
            if(!newDOs.contains(doj)) {
                doj.addPropertyChangeListener(dataObjectListener);
                newDOs.add(doj);
            }
        }
            
        synchronized (dataObjects) {
            this.dataObjects.removeAll(newDOs);
            for (Iterator it = this.dataObjects.iterator(); it.hasNext();) {
                DataObject dataObject = (DataObject) it.next();
                dataObject.removePropertyChangeListener(this.dataObjectListener);
            }
            this.dataObjects.clear();
            this.dataObjects.addAll(newDOs);
            this.dataObjectListener.setDataObjects(newDOs);
        }
    }
    
    private static class WPCL extends WeakReference implements PropertyChangeListener, MDRChangeListener, Runnable {
        
        private List dataObjects = null;
        private MDRepository repository;
        
        public WPCL(AutoCommenter ac) {
            super(ac, Utilities.activeReferenceQueue());
            initMDRListener();
        }
        
        public synchronized void setDataObjects(List dos) {
            this.dataObjects = dos;
        }
        
        public void propertyChange(PropertyChangeEvent evt) {
            AutoCommenter ac = (AutoCommenter) get();
            if (ac == null) return;
            DataObject doj = (DataObject) evt.getSource();
            if(evt.getPropertyName().equals(DataObject.PROP_VALID)){
                synchronized (this) {
                    if (dataObjects != null) {
                        doj.removePropertyChangeListener(this);
                        if (dataObjects.remove(doj))
                            ac.refreshFromSource();
                    }
                }
            }
        }

        public void change(MDRChangeEvent e) {
            AutoCommenter ac = (AutoCommenter) get();
            if (ac == null) return;
            
            if ((e instanceof ExtentEvent) && e.getType() == ExtentEvent.EVENT_EXTENT_DELETE) {
                ac.refreshFromSource();
            }
        }

        public void run() {
            if (dataObjects != null) {
                for (Iterator it = dataObjects.iterator(); it.hasNext();) {
                    DataObject d = (DataObject) it.next();
                    d.removePropertyChangeListener(this);
                }
            }
            if (repository != null) {
                repository.removeListener(this);
            }
        }
        
        /**
         * listens mdr in order to reflect changes like platform change, ...
         */ 
        private void initMDRListener() {
            this.repository = JavaMetamodel.getDefaultRepository();
            this.repository.addListener(this);
        }
    }

    /**
     * async refresh
     */ 
    public void refreshFromSource() {
        QUEUE.post(new Runnable() {
            public void run() {
                refreshFromSourceImpl();
                fireAutocommentChangeEvent();
            }
        });
    }
    
    /**
     * updates element el with new javadoc doc.
     * The update runs asynchronously and clients are notified via
     * {@link AutoCommentChangeListener#elementUpdated}
     * @param el
     * @param doc
     */ 
    public void modifyJavadoc(final AutoCommenter.Element el, final JavaDoc doc) {
        QUEUE.post(new Runnable() {
            public void run() {
                try {
                    JavaMetamodel.getDefaultRepository().beginTrans(true);
                    try {
                        el.setJavaDoc(doc);
                        el.checkError();
                        fireElementUpdatedEvent(el);
                    } finally {
                        JavaMetamodel.getDefaultRepository().endTrans();
                    }
                } catch (JmiException e) {
                    ErrorManager.getDefault().notify(e);
                }
            }
        });
    }
    
    /**
     * tries to auto correct javadoc of the element. 
     * The method runs asynchronously and clients are notified via
     * {@link AutoCommentChangeListener#elementUpdated}
     * @param element an elemnt to auto correct
     * @param doc javadoc that should be applied before correction; can be
     *              null
     */ 
    public void autoCorrectJavadoc(final AutoCommenter.Element element, final JavaDoc doc) {
        QUEUE.post(new Runnable() {
            public void run() {
                try {
                    JavaMetamodel.getDefaultRepository().beginTrans(true);
                    try {
                        if (doc != null) {
                            element.setJavaDoc(doc);
                        }
                        element.autoCorrect();
                        element.checkError();
                        fireElementUpdatedEvent(element);
                    } finally {
                        JavaMetamodel.getDefaultRepository().endTrans();
                    }
                } catch (JmiException e) {
                    ErrorManager.getDefault().notify(e);
                } catch (org.openide.src.SourceException e) {
                    ErrorManager.getDefault().notify(e);
                }
            }
        });
    }
    
    private void refreshFromSourceImpl() {
        updateDataObjects();
        List dobjs;
        synchronized (this.dataObjects) {
            dobjs = new ArrayList(this.dataObjects);
        }
        elements = new ArrayList(dobjs.size());
        try {
            JavaMetamodel.getDefaultRepository().beginTrans(false);
            try {
                for (Iterator it = dobjs.iterator(); it.hasNext();) {
                    DataObject d = (DataObject) it.next();
                    Resource r = JavaMetamodel.getManager().getResource(d.getPrimaryFile());
                    if (r != null) {        
                        addCommentable(r);
                    }
                }
            } finally {
                JavaMetamodel.getDefaultRepository().endTrans();
            }
        } catch (JmiException ex) {
            ErrorManager.getDefault().notify(ex);
        }
    }

    private void addCommentable(Resource r){
        List/**/ classes = JMIUtils.getAllClasses(r);
        for (Iterator it = classes.iterator(); it.hasNext();) {
            JavaClass jc = (JavaClass) it.next();
            if (jc.isValid()) {
                addElements(jc);
            }
        }
    }

    private void prepareListModel( DefaultListModel listModel, int mask, boolean pckg, int err_mask ) {
        for(Iterator it = elements.iterator(); it.hasNext(); ) {
            Element el = (Element) it.next();

            if ( acceptElement( el, mask, pckg, err_mask ) ) {
                listModel.addElement(el);
            }
        }
    }

    static boolean acceptElement( Element el, int mask, boolean pckg, int err_mask ) {

        // Test whether the element is accepted by error mask

        if ( ( el.getErrorNumber() & err_mask ) == 0 )
            return false;

        // Test whether the element is accepted by access mask
        int access = el.getDescriptor().getEffectiveAccess();
        if (access == 0) 
            return pckg;
        else 
            return (access & mask) > 0;
    }

    DefaultListModel prepareListModel( int mask, boolean pckg, int err_mask ) {
        DefaultListModel dm = new DefaultListModel();
        prepareListModel( dm, mask, pckg, err_mask );
        return dm;
    }

    private void addElements(JavaClass classElement ) {
        elements.add(createAutoCommenterElement(classElement));

        List features = classElement.getFeatures();
        for (Iterator it = features.iterator(); it.hasNext();) {
            Object feature = it.next();
            if (feature instanceof JavaClass || !(feature instanceof ClassMember))
                continue;
            Element el = createAutoCommenterElement((ClassMember) feature);
            if (el != null)
                elements.add(el);
        }
    }
    
    /**
     * factory method for AutoCommenter elements
     * @param element resource member to comment
     * @return commentable or null
     */ 
    public static Element createAutoCommenterElement(ClassMember element) {
        Element jdElement = null;
        if (element instanceof JavaClass) {
            // class + interface + enum + ann type
            jdElement = new Element.Class((JavaClass) element);
        } else if (element instanceof org.netbeans.jmi.javamodel.Field) {
            // field + enum constant
            jdElement = new Element.Field((org.netbeans.jmi.javamodel.Field) element);
        } else if (element instanceof org.netbeans.jmi.javamodel.Constructor) {
            jdElement = new Element.Constructor((org.netbeans.jmi.javamodel.Constructor) element);
        } else if (element instanceof org.netbeans.jmi.javamodel.Method) {
            jdElement = new Element.Method((org.netbeans.jmi.javamodel.Method) element);
        } else if (element instanceof Attribute) {
            jdElement = new Element.Field((Attribute) element);
        }
        if (jdElement != null) {
            jdElement.initialize();
        }
        return jdElement;
    }
    
    /** innerclass holds the element and the informations about comment errors */

    static abstract class Element {

        private DefaultListModel errorList;

        protected final ClassMember srcElement;
        private int srcError = JDC_OK;
            
        private JavaDoc javadoc;
        
        private ElementDescriptor desc;

        protected Element(ClassMember srcElement) {
            this.srcElement = srcElement;
        }
        
        /**
         * initialize element properties for work inside the awt event queue;
         * should be invoked just from the factory
         * @throws JmiException
         */ 
        protected final void initialize() throws JmiException {
            javadoc = createJavaDoc();
            desc = new ElementDescriptor(this, getNameFormat());
            checkError();
        }
        
        /** needs to be run inside mdr transaction;
         *  clients should use this outside of the awt event queue.
         */
        public final ElementDescriptor getDescriptor() throws JmiException {
            assert desc != null;
            return desc;
        }

        public final ClassMember getSrcElement() {
            return srcElement;
        }

        public final int getErrorNumber() {
            return srcError;
        }

        public final void viewSource() {
            AutoCommenter.QUEUE.post(new Runnable() {
                int state = 0;
                EditorCookie ec;
                int offset;
                DataObject dobj;
                
                public void run() {
                    switch (state) {
                        case 0:
                            findOffset();
                            break;
                        case 1:
                            open();
                            break;
                    }
                }
                
                void findOffset() {
                    try {
                        JavaMetamodel.getDefaultRepository().beginTrans(false);
                        try {
                            Resource r = srcElement.getResource();
                            if (r == null) return;
                            offset = JavaMetamodel.getManager().
                                                getElementPosition(srcElement).getBegin().getOffset();
                            dobj = JavaMetamodel.getManager().getDataObject(r);
                            if (dobj == null) return;
                            ec = (EditorCookie) dobj.getCookie(EditorCookie.class);
                            if (ec == null) return;
                            ++state;
                            EventQueue.invokeLater(this);
                        } finally {
                            JavaMetamodel.getDefaultRepository().endTrans();
                        }
                    } catch (JmiException e) {
                        ErrorManager.getDefault().notify(e);
                        return;
                    }
                }
            
                void open() {
                    ec.open();
                    JEditorPane[] epane = ec.getOpenedPanes();
                    if (epane != null && epane.length > 0) {
                        epane[0].getCaret().setDot(offset);
                        epane[0].requestFocus();
                    }
                }
            });
        }

        public synchronized final DefaultListModel getErrorList() {
            return errorList;
        }

        protected abstract String[] getNotPermittedTags();

        /**
         * check if javadoc tags are valid.
         * implementor should use descriptor instead of jmi element
         * @return
         */ 
        protected abstract boolean elementTagsOk(DefaultListModel errList);
        
        /**
         * needs MDR transaction
         * @throws SourceException
         */ 
        public abstract void autoCorrect() throws SourceException;

        protected abstract JavaDoc createJavaDoc();
        
        public final JavaDoc getJavaDoc() {
            assert javadoc != null;
            return javadoc;
        }
        
        /**
         * set new javadoc; needs mdr transaction
         * @param doc new javadoc
         * @throws JmiException
         */ 
        public final void setJavaDoc(final JavaDoc doc) throws JmiException {
            if (doc == null) throw new NullPointerException("doc"); // NOI18N

            this.srcElement.setJavadocText(doc.getRawText());
            this.javadoc = createJavaDoc();
        }

        protected abstract Format getNameFormat();

        protected abstract String typeToString();

        static boolean isPermittedTag(JavaDocTag tag, String[] notPermittedTags ) {
            String tagName = tag.name();

            for ( int i = 0; i < notPermittedTags.length; i++ ) {
                if ( tagName.equals( notPermittedTags[i] ) )
                    return false;
            }

            return true;
        }

        private static boolean isEmptyString( String string ) {
            return string == null || string.trim().length() <= 0;
        }

        /** Checks syntax of the tags
         */

        private boolean isOkTag(JavaDocTag tag, DefaultListModel errList ) {
            if ( isEmptyString( tag.text() ) ) {
                log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_EmptyTag" ),   //NOI18N
                                      new Object[] { tag.name()  } ) );
                return false;
            }

            if ( tag instanceof JavaDocTag.See ) {
                int len;
                String text;
                JavaDocTag.See seetag = (JavaDocTag.See) tag;
                
                if ((seetag.referencedClassName() != null) || (seetag.referencedMemberName() != null)) 
                    return true;
                text=tag.text();
                len = text.length();
                if (len >= 2) {
                    char first=text.charAt(0);
                    char last=text.charAt(len-1);
                    
                    if (first=='"' && last==first)
                        return true;
                    if (first=='<' && last=='>')
                        return true;
                }
                log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_InvalidTag" ),  //NOI18N
                                  new Object[] { seetag } ));  //NOI18N
                return false;
            }
            else if ( tag instanceof JavaDocTag.Param ) {
                if ( isEmptyString( ((JavaDocTag.Param)tag).parameterName() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ParamNoName" ),    //NOI18N
                                          new Object[] { tag.name() } ) );
                    return false;
                }
                if ( isEmptyString( ((JavaDocTag.Param)tag).parameterComment() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ParamNoDescr" ),   //NOI18N
                                          new Object[] { tag.name(), ((JavaDocTag.Param)tag).parameterName()  } ) );
                    return false;
                }
            }
            else if ( tag instanceof JavaDocTag.Throws ) {
                if ( isEmptyString( ((JavaDocTag.Throws)tag).exceptionName() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ThrowsNoName" ),   //NOI18N
                                          new Object[] { tag.name() } ) );
                    return false;
                }
                if ( isEmptyString( ((JavaDocTag.Throws)tag).exceptionComment() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ThrowsNoDescr" ),  //NOI18N
                                          new Object[] { tag.name(), ((JavaDocTag.Throws)tag).exceptionName()  } ) );
                    return false;
                }
            }
            else if ( tag instanceof JavaDocTag.SerialField ) {
                if ( isEmptyString( ((JavaDocTag.SerialField)tag).fieldName() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_SerialFieldNoName" ),  //NOI18N
                                          new Object[] { tag.name() } ) );
                    return false;
                }
                if ( isEmptyString( ((JavaDocTag.SerialField)tag).fieldType() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_SerialFieldNoType" ),  //NOI18N
                                          new Object[] { tag.name(), ((JavaDocTag.SerialField)tag).fieldName()  } ) );
                    return false;
                }

                if ( isEmptyString( ((JavaDocTag.SerialField)tag).description() ) ) {
                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_SerialFieldNoDescr" ), //NOI18N
                                          new Object[] { tag.name(), ((JavaDocTag.SerialField)tag).fieldName()  } ) );
                    return false;
                }
            }
            return true;
        }

        protected final boolean isMultipleTags(String tag, DefaultListModel errList) {
            // Check for multiple tags
            boolean error = false;
            JavaDocTag[] tags = getJavaDoc().getTags(tag);
            if ( tags.length > 1) {
                log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_DuplicatedTag" ),  //NOI18N
                                      new Object[] { tags[0].name() } ) );
                error = true;
            }
            return error;
        }
        
        /**
         * check current javadoc.
         */ 
        public final void checkError() {
            
            DefaultListModel _errorList = new DefaultListModel();

            JavaDoc jdoc = getJavaDoc();

            if ( jdoc.isEmpty() ) {
                _errorList.addElement( ResourceUtils.getBundledString( "ERR_JavadocMissing" ) ); //NOI18N
                synchronized(this) {
                    srcError = JDC_MISSING;
                    this.errorList = _errorList;
                }
                desc.recomputeIcon();
                return;
            }

            JavaDocTag[] tags = jdoc.getTags();
            boolean error = false;

            if ( jdoc.getText() == null || jdoc.getText().trim().length() <= 0 ) {
                _errorList.addElement( ResourceUtils.getBundledString( "ERR_EmptyText" ) );  //NOI18N
                error = true;
            }

            for ( int i = 0; i < tags.length; i ++ ) {
                if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) {
                    _errorList.addElement( MessageFormat.format( ResourceUtils.getBundledString( "ERR_BadTag" ), //NOI18N
                                          new Object[] { tags[i].name(), typeToString() } ) );
                    error = true;
                    continue;
                }

                if (!isOkTag(tags[i], _errorList)) {
                    error = true;
                    continue;
                }
            }
            
            if (isMultipleTags(TAG_SINCE, _errorList)) {
                error = true;
            }
            
            if (isMultipleTags(TAG_DEPRECATED, _errorList)) {
                error = true;
            }
            
            if (!elementTagsOk(_errorList)) {
                error = true;
            }

            if ( !error ) {
                _errorList.addElement( ResourceUtils.getBundledString( "ERR_JavadocOK" ) );  //NOI18N
            }

            synchronized (this) {
                srcError = error ? JDC_ERROR : JDC_OK;
                this.errorList = _errorList;
            }
            desc.recomputeIcon();
        }
        
        /**
         * check if javadoc needs some correction; implementors should use
         * descriptor instead of jmi calls
         * @return
         */ 
        public boolean isCorrectable() {
            assert this.javadoc != null;
            assert this.desc != null;
            JavaDocTag[] tags = getJavaDoc().getTags();

            for ( int i = 0; i < tags.length; i ++ ) {
                if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) {
                    return true;
                }
            }

            return false;
        }

        /**
         * needs mdr transaction
         * @param jdoc
         * @throws SourceException
         */ 
        protected void autoCorrect( JavaDoc jdoc ) throws SourceException {
            JavaDocTag[] tags = jdoc.getTags();
            ArrayList correctedTags = new ArrayList( tags.length );
            String correctedText;

            correctedText = jdoc.getText();

            if ( correctedText == null ) {
                correctedText = ""; // NOI18N
            }

            for ( int i = 0; i < tags.length; i ++ ) {
                if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) {
                    continue;
                }
                correctedTags.add( tags[i] );
            }

            jdoc.changeTags( (JavaDocTag[])correctedTags.toArray( new JavaDocTag[ correctedTags.size() ] ), JavaDoc.SET  );
        }
        
        private static void log(DefaultListModel errList, String txt) {
            if (errList != null) {
                errList.addElement(txt);
            }
        }


        static class Class extends Element {

            private static final String[] NOT_PERMITTED_TAGS = {
                TAG_EXCEPTION,
                TAG_PARAM,
                TAG_RETURN,
                TAG_SERIAL,
                TAG_SERIALDATA,
                TAG_SERIALFIELD,
                TAG_THROWS,
            };

            private static final Format nameFormat = SourceNodes.createElementFormat("{C}"); // NOI18N
            
            protected Class( JavaClass element ) {
                super( element );
            }

            public String[] getNotPermittedTags() {
                return NOT_PERMITTED_TAGS;
            }
            
            protected boolean elementTagsOk(DefaultListModel errList) {
                boolean error = false;
                if (this.isMultipleTags(TAG_VERSION, errList)) {
                    error = true;
                }
                return !error;
            }

            public void autoCorrect() throws SourceException {
                super.autoCorrect( getJavaDoc() );
                setJavaDoc(getJavaDoc());
            }

            public String typeToString() {
                String type;
                if (this.srcElement instanceof JavaEnum) {
                    type = "enum"; // NOI18N
                } else if (this.srcElement instanceof AnnotationType) {
                    type = "annotation type"; // NOI18N
                } else {
                    type = Modifier.isInterface(getDescriptor().getModifiers())
                            ? "interface" : "class"; // NOI18N
                }
                return type;
            }

            protected JavaDoc createJavaDoc() {
                String s = srcElement.getJavadocText();
                JavaDoc javadoc = JavaDocSupport.createClassJavaDoc(s);
                return javadoc;
            }

            public Format getNameFormat () {
                return nameFormat;
            }

        }

        static class Field extends Element {

            private static final String[] NOT_PERMITTED_TAGS = {
                TAG_AUTHOR,
                TAG_EXCEPTION,
                TAG_PARAM,
                TAG_RETURN,
                TAG_SERIALDATA,
                TAG_THROWS,
                TAG_VERSION
            };

            private static final Format nameFormat = SourceNodes.createElementFormat("{n}"); // NOI18N
            
            protected Field(org.netbeans.jmi.javamodel.Field element ) {
                super( element );
            }
            
            protected Field(Attribute element ) {
                super( element );
            }
            
            protected JavaDoc createJavaDoc() {
                String s = srcElement.getJavadocText();
                JavaDoc javaDoc = JavaDocSupport.createFieldJavaDoc(s);
                return javaDoc;
            }

            public String[] getNotPermittedTags() {
                return NOT_PERMITTED_TAGS;
            }

            public String typeToString() {
                return this.srcElement instanceof Field? "field": "attribute"; // NOI18N
            }

            protected boolean elementTagsOk(DefaultListModel errList) {
                boolean error = false;
                if (this.isMultipleTags(TAG_SERIAL, errList)) {
                    error = true;
                }
                
                return !error;
            }

            public void autoCorrect() throws SourceException {
                super.autoCorrect( getJavaDoc() );
                setJavaDoc(getJavaDoc());
            }

            public Format getNameFormat () {
                return nameFormat;
            }
        }

        static class Constructor extends Element {

            private static final String[] NOT_PERMITTED_TAGS = {
                TAG_AUTHOR,
                TAG_SERIAL,
                TAG_SERIALFIELD,
                TAG_VERSION,
                TAG_RETURN
            };

            private static final Format nameFormat = SourceNodes.createElementFormat("{n}({p,,,\",\"})"); // NOI18N

            protected Constructor(org.netbeans.jmi.javamodel.CallableFeature element) {
                super( element );
            }
            
            protected JavaDoc createJavaDoc() {
                String s = srcElement.getJavadocText();
                JavaDoc javadoc = JavaDocSupport.createMethodJavaDoc(s);
                return javadoc;
            }

            public String[] getNotPermittedTags() {
                return NOT_PERMITTED_TAGS;
            }

            public String typeToString() {
                return "constructor"; // NOI18N
            }

            protected boolean elementTagsOk(DefaultListModel errList) {
                return elementTagsOk( null, false, errList );
            }

            private boolean elementTagsOk( ArrayList correctedTags, boolean checkOnly, DefaultListModel errList ) {

                boolean error = false;

                // Check param tags

                JavaDoc jdoc = getJavaDoc();
                JavaDocTag.Param[] ptags = ((JavaDoc.Method) jdoc).getParamTags();
                boolean[] ptags_found = new boolean[ ptags.length ];
                
                // Check if all parameters for the method are in the javadoc
                // and if there are any parameter tag duplicates.
                String[] params = getDescriptor().getParameterNames();
                for (int j = 0; j < params.length; j++) {
                    String param = params[j];
                    boolean tagFound = false;
                    boolean duplicateTagAlreadyFound = false;
                    for (int i = 0 ; i < ptags.length ; i++) {
                        if (ptags[i].parameterName() != null && ptags[i].parameterName().equals(param)) {
                            ptags_found[i] = true;
                            if (!tagFound) {
                                tagFound = true;
                            } else if (! duplicateTagAlreadyFound) {
                                if ( checkOnly ) {
                                    return false;
                                } else if ( correctedTags == null ) {
                                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_DuplicatedParamTag" ), //NOI18N
                                                          new Object[] { param } ) );
                                }
                                error = true;
                                duplicateTagAlreadyFound = true;
                            }
                        }
                    }
                        
                    if (! tagFound ) {
                        if ( checkOnly ) {
                            return false;
                        } else if ( correctedTags == null ) {
                            error = true;
                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoTagForParam" ),  //NOI18N
                                                  new Object[] { param } ) );
                        }
                        else {
                            correctedTags.add( JavaDocSupport.createParamTag( TAG_PARAM, param ) );
                        }
                    }
                }
                        
                for( int i = 0; i < ptags.length; i++ ) {
                    if ( !ptags_found[i] ) {
                        if ( checkOnly ) {
                            return false;
                        }
                        else if ( correctedTags == null ) {
                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoSuchParam" ),    //NOI18N
                                                  new Object[] { ptags[i].name(), ptags[i].parameterName() } ) );
                        }
                        error = true;
                    }
                    else if ( correctedTags != null ) {
                        correctedTags.add( ptags[i] );
                    }


                }
                // Check throws tags


                JavaDocTag.Throws[] ttags = ((JavaDoc.Method) getJavaDoc()).getThrowsTags();
                boolean[] ttags_found = new boolean[ ttags.length ];
                String[] excs = getDescriptor().getThrowFQNNames();

                // Check if all exceptions for the method are in the javadoc
                // and if there are any exception tag duplicates.
                for (int j = 0; j < excs.length; j++) {
                    String excFQN = excs[j];
                    boolean tagFound = false;
                    boolean duplicateTagAlreadyFound = false;
                    for (int i = 0 ; i < ttags.length ; i++) {
                        //
                        String tagExId = ttags[i].exceptionName().replaceFirst("\\.+\\z", "");
                        //
                        
                        
                        if (tagExId.length() > 0 && excFQN.endsWith(tagExId)) {
                            ttags_found[i] = true;
                            if (!tagFound) {
                                tagFound = true;
                            } else if (! duplicateTagAlreadyFound){
                                if ( checkOnly ) {
                                    return false;
                                }
                                else if ( correctedTags == null ) {
                                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_DuplicatedExceptionTag" ), //NOI18N
                                                          new Object[] { excFQN }));
                                }
                                error = true;
                                duplicateTagAlreadyFound = true;
                            }
                        }
                    }
                        
                    if (! tagFound ) {
                        if ( checkOnly ) {
                            return false;
                        } else if ( correctedTags == null ) {
                            error = true;
                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoTagForException" ),  //NOI18N
                                                  new Object[] { excFQN }));
                        }
                        else {
                            correctedTags.add( JavaDocSupport.createThrowsTag( TAG_THROWS, excFQN));
                        }
                    }
                }
                        
                for( int i = 0; i < ttags.length; i++ ) {
                    if ( !ttags_found[i] ) {
                        if ( checkOnly ) {
                            return false;
                        }
                        else if ( correctedTags == null ) {
                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoSuchException" ),    //NOI18N
                                                  new Object[] { ttags[i].name(), ttags[i].exceptionName() } ) );
                        }
                        error = true;
                    }
                    else if ( correctedTags != null ) {
                        correctedTags.add( ttags[i] );
                    }


                }

                return !error;
            }

            public boolean isCorrectable () {
                if ( super.isCorrectable() )
                    return true;

                return !elementTagsOk( null, true, null );
            }

            public void autoCorrect() throws SourceException {
                super.autoCorrect( getJavaDoc() );
                setJavaDoc(getJavaDoc());
            }

            public void autoCorrect( JavaDoc jDoc ) throws SourceException {
                JavaDoc.Method jdTemp = JavaDocSupport.createMethodJavaDoc(getJavaDoc().getRawText());

                // create comment without throws and params

                JavaDocTag tags[] = jdTemp.getTags();
                ArrayList stdTags = new ArrayList( tags.length );

                for( int i = 0; i < tags.length; i++ ) {
                    if ( !( tags[i] instanceof JavaDocTag.Param ) &&
                            !( tags[i] instanceof JavaDocTag.Throws ) ) {
                        stdTags.add( tags[i] );
                    }
                }

                jdTemp.changeTags( (JavaDocTag[])stdTags.toArray( new JavaDocTag[ stdTags.size() ] ), JavaDoc.SET  );

                super.autoCorrect( jdTemp );

                ArrayList correctedTags = new ArrayList();
                elementTagsOk( correctedTags, false, null );

                // Build all tags collection

                ArrayList allTags = new ArrayList( correctedTags.size() + tags.length );
                tags = jdTemp.getTags();
                for( int i = 0; i < tags.length; i++ ) {
                    allTags.add( tags[i] );
                }
                allTags.addAll( correctedTags );

                jDoc.changeTags( (JavaDocTag[])allTags.toArray( new JavaDocTag[ allTags.size() ] ), JavaDoc.SET  );
            }

            public Format getNameFormat () {
                return nameFormat;
            }

        }

        static class Method extends Constructor {

            private static final Format nameFormat = SourceNodes.createElementFormat("{n}({p,,,\",\"})"); // NOI18N

            private static final String[] NOT_PERMITTED_TAGS = {
                TAG_AUTHOR,
                TAG_SERIAL,
                TAG_SERIALFIELD,
                TAG_VERSION
            };
            
            Method(org.netbeans.jmi.javamodel.Method element) {
                super( element );
            }

            public String typeToString() {
                return "method"; // NOI18N
            }

            public String[] getNotPermittedTags() {
                return NOT_PERMITTED_TAGS;
            }

            protected boolean elementTagsOk(DefaultListModel errList) {
                boolean superOk = super.elementTagsOk(errList);
                boolean retOk = checkReturnType(false, errList);
                return !superOk ? false : retOk;
            }

            private boolean checkReturnType(boolean checkOnly, DefaultListModel errList) {

                boolean retOk = true;

                String retFQN = getDescriptor().getTypeFQNName();
                JavaDocTag[] retTags = getJavaDoc().getTags(TAG_RETURN);
                
                boolean isVoid = "void".equals(retFQN); // NOI18N

                if (isVoid && retTags.length > 0) {
                    if ( checkOnly ) {
                        return false;
                    }
                    log(errList, ResourceUtils.getBundledString( "ERR_ReturnForVoid" ) );  //NOI18N
                    retOk = false;
                } else if (!isVoid && retTags.length <= 0) {
                    if ( checkOnly ) {
                        return false;
                    }
                    log(errList, ResourceUtils.getBundledString( "ERR_NoReturn" ) );  //NOI18N
                    retOk = false;
                } else if (!isVoid && retTags.length > 1) {
                    if ( checkOnly) {
                        return false;
                    }
                    log(errList, ResourceUtils.getBundledString( "ERR_DuplicatedReturn" ) );   //NOI18N
                    retOk = false;
                }

                return retOk;
            }

            public boolean isCorrectable() {

                if ( super.isCorrectable() )
                    return true;

                return !checkReturnType(true, null);
            }

            public void autoCorrect() throws SourceException {
                JavaDoc jdTemp = JavaDocSupport.createMethodJavaDoc( getJavaDoc().getRawText() );
                super.autoCorrect( jdTemp );

                if (!checkReturnType(true, null) ) {
                    String retFQN = getDescriptor().getTypeFQNName();
                    if (!"void".equals(retFQN)) { // NOI18N
                        jdTemp.changeTags(
                            new JavaDocTag[] { JavaDocSupport.createTag( TAG_RETURN, "" ) }, // NOI18N
                            JavaDoc.ADD );
                    } else {
                        JavaDocTag toRemove[] = jdTemp.getTags( TAG_RETURN );

                        jdTemp.changeTags( toRemove, JavaDoc.REMOVE );
                    }
                }

                getJavaDoc().setRawText( jdTemp.getRawText() );
                setJavaDoc(getJavaDoc());
            }

            public Format getNameFormat () {
                return nameFormat;
            }
        }
    }

    public interface AutoCommentChangeListener extends EventListener {
        /**
         * notifies that auto commenter computed new list of commantable elements. 
         */ 
        public void listChanged();
        /**
         * notifies about element's javadoc update
         * @param el
         */ 
        public void elementUpdated(AutoCommenter.Element el);
    }
    
    /** Registers PropertyChangeListener to receive events.
     * @param listener The listener to register.
     */
    public synchronized void addAutoCommentChangeListener(AutoCommentChangeListener listener) throws java.util.TooManyListenersException {
        if (autoCommentChangeListener != null) {
            throw new java.util.TooManyListenersException();
        }
        autoCommentChangeListener = listener;
    }
    
    /** Removes PropertyChangeListener from the list of listeners.
     * @param listener The listener to remove.
     */
    public synchronized void removeAutoCommentChangeListener(AutoCommentChangeListener listener) {
        autoCommentChangeListener = null;
    }
    
    /** Notifies the registered listener about the event.
     */
    private void fireAutocommentChangeEvent() {
        if (autoCommentChangeListener == null) return;
        autoCommentChangeListener.listChanged();
    }
    
    private void fireElementUpdatedEvent(AutoCommenter.Element el) {
        if (autoCommentChangeListener == null) return;
        autoCommentChangeListener.elementUpdated(el);
    }
}
... 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.