KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javadoc > comments > AutoCommenter


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.javadoc.comments;
21
22 import java.text.MessageFormat JavaDoc;
23 import java.text.Format JavaDoc;
24 import javax.swing.*;
25 import javax.jmi.reflect.JmiException;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.lang.reflect.Modifier JavaDoc;
28
29 import org.openide.src.JavaDoc;
30 import org.openide.cookies.EditorCookie;
31 import org.openide.cookies.SourceCookie;
32 import org.openide.nodes.Node;
33 import org.openide.loaders.DataObject;
34 import org.openide.loaders.DataFolder;
35 import org.openide.util.Utilities;
36 import org.openide.util.RequestProcessor;
37 import org.openide.util.Lookup;
38 import org.openide.ErrorManager;
39 import org.openide.filesystems.FileObject;
40 import org.openide.src.JavaDocTag;
41 import org.openide.src.SourceException;
42 import org.openide.src.JavaDocSupport;
43 import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
44 import org.netbeans.modules.java.ui.nodes.SourceNodes;
45 import org.netbeans.jmi.javamodel.*;
46 import org.netbeans.api.mdr.events.MDRChangeListener;
47 import org.netbeans.api.mdr.events.MDRChangeEvent;
48 import org.netbeans.api.mdr.events.ExtentEvent;
49 import org.netbeans.api.mdr.events.InstanceEvent;
50 import org.netbeans.api.mdr.MDRepository;
51
52 import java.beans.PropertyChangeListener JavaDoc;
53 import java.beans.PropertyChangeEvent JavaDoc;
54 import java.util.*;
55 import java.util.List JavaDoc;
56 import java.awt.*;
57 import org.netbeans.modules.javacore.api.JavaModel;
58
59 /** Contains static methods for generating default JavaDoc comments for
60  * java data object hierarchy elements.
61  *
62  * Checks for Comment errors in JavaNodes
63  *
64  * @author Petr Hrebejk
65  */

66 public final class AutoCommenter extends Object JavaDoc implements JavaTagNames {
67
68     public static final int JDC_OK = 1;
69     public static final int JDC_MISSING = 2;
70     public static final int JDC_ERROR = 4;
71     
72     private static final RequestProcessor QUEUE = new RequestProcessor("Auto CommenterQueue"); // NOI18N
73

74     /** List of <code>DataObject</code>s. */
75     private final ArrayList dataObjects;
76     ArrayList elements;
77     Node[] nodes;
78     /** listens to all <code>dataobjects</code> elements*/
79     private final WPCL dataObjectListener = new WPCL(this);
80
81     /** Utility field holding the PropertyChangeListener. */
82     private AutoCommentChangeListener autoCommentChangeListener = null;
83
84     /** Creates an empty AutoCommenter */
85     AutoCommenter() {
86         this( new Node[0] );
87     }
88
89     /** Creates Auto commenter for nodes */
90     AutoCommenter ( Node[] nodes ) {
91         dataObjects = new ArrayList();
92         this.nodes = nodes;
93     }
94     
95     private void updateDataObjects() {
96         
97         List JavaDoc newDOs = new LinkedList();
98         
99         for (int i = 0; i < nodes.length; i++) {
100             DataFolder df = (DataFolder) nodes[i].getCookie(DataFolder.class);
101             Object JavaDoc cookie = null;
102             if(df != null && df.isValid()){
103                 DataObject[] children = df.getChildren();
104                 for (int n = 0; n < children.length; n++){
105                     final DataObject child = children[n];
106                     cookie = child.getCookie(SourceCookie.class);
107                     FileObject childFO = child.getPrimaryFile();
108                     if (cookie != null && childFO.canWrite()
109                             && !"class".equalsIgnoreCase(childFO.getExt())){ // NOI18N
110
if(!newDOs.contains(child)){
111                             child.addPropertyChangeListener(dataObjectListener);
112                             newDOs.add(child);
113                         }
114                     }
115                 }
116                 continue;
117             } else {
118                 Lookup lkp = nodes[i].getLookup();
119                 cookie = lkp.lookup(org.netbeans.jmi.javamodel.Element.class);
120                 if (cookie == null) {
121                     cookie = lkp.lookup(SourceCookie.class);
122                 }
123             }
124             final DataObject doj = (DataObject) nodes[i].getCookie(DataObject.class);
125             if ( cookie == null || doj == null || !doj.getPrimaryFile().canWrite()
126                     || "class".equalsIgnoreCase(doj.getPrimaryFile().getExt())) // NOI18N
127
continue;
128             
129             if(!newDOs.contains(doj)) {
130                 doj.addPropertyChangeListener(dataObjectListener);
131                 newDOs.add(doj);
132             }
133         }
134             
135         synchronized (dataObjects) {
136             this.dataObjects.removeAll(newDOs);
137             for (Iterator it = this.dataObjects.iterator(); it.hasNext();) {
138                 DataObject dataObject = (DataObject) it.next();
139                 dataObject.removePropertyChangeListener(this.dataObjectListener);
140             }
141             this.dataObjects.clear();
142             this.dataObjects.addAll(newDOs);
143             this.dataObjectListener.setDataObjects(newDOs);
144         }
145     }
146     
147     private static class WPCL extends WeakReference JavaDoc implements PropertyChangeListener JavaDoc, MDRChangeListener, Runnable JavaDoc {
148         
149         private List JavaDoc dataObjects = null;
150         private MDRepository repository;
151         
152         public WPCL(AutoCommenter ac) {
153             super(ac, Utilities.activeReferenceQueue());
154             initMDRListener();
155         }
156         
157         public synchronized void setDataObjects(List JavaDoc dos) {
158             this.dataObjects = dos;
159         }
160         
161         public void propertyChange(PropertyChangeEvent JavaDoc evt) {
162             AutoCommenter ac = (AutoCommenter) get();
163             if (ac == null) return;
164             DataObject doj = (DataObject) evt.getSource();
165             if(evt.getPropertyName().equals(DataObject.PROP_VALID)){
166                 synchronized (this) {
167                     if (dataObjects != null) {
168                         doj.removePropertyChangeListener(this);
169                         if (dataObjects.remove(doj))
170                             ac.refreshFromSource();
171                     }
172                 }
173             }
174         }
175
176         public void change(MDRChangeEvent e) {
177             AutoCommenter ac = (AutoCommenter) get();
178             if (ac == null) return;
179             
180             if ((e instanceof ExtentEvent) && e.getType() == ExtentEvent.EVENT_EXTENT_DELETE) {
181                 ac.refreshFromSource();
182             } else if (e instanceof InstanceEvent) {
183                 InstanceEvent ie = (InstanceEvent) e;
184                 handleElementDelete(ie);
185             }
186         }
187         
188         private void handleElementDelete(InstanceEvent e) {
189             final Object JavaDoc instance = e.getInstance();
190             if (e.getType() != InstanceEvent.EVENT_INSTANCE_DELETE || !(instance instanceof ClassMember)) return;
191             
192             AutoCommenter ac = (AutoCommenter) get();
193             if (ac == null) return;
194             
195             for (Iterator it = ac.elements.iterator(); it.hasNext();) {
196                 Element element = (Element) it.next();
197                 if (instance == element.getSrcElement()) {
198                     element.isValid = false;
199                     return;
200                 }
201             }
202         }
203
204         public void run() {
205             if (dataObjects != null) {
206                 for (Iterator it = dataObjects.iterator(); it.hasNext();) {
207                     DataObject d = (DataObject) it.next();
208                     d.removePropertyChangeListener(this);
209                 }
210             }
211             if (repository != null) {
212                 repository.removeListener(this);
213             }
214         }
215         
216         /**
217          * listens mdr in order to reflect changes like platform change, ...
218          */

219         private void initMDRListener() {
220             this.repository = JavaModel.getJavaRepository();
221             this.repository.addListener(this);
222         }
223     }
224
225     /**
226      * async refresh
227      */

228     public void refreshFromSource() {
229         QUEUE.post(new Runnable JavaDoc() {
230             public void run() {
231                 refreshFromSourceImpl();
232                 fireAutocommentChangeEvent();
233             }
234         });
235     }
236     
237     /**
238      * updates element <code>el</code> with new javadoc <code>doc</code>.
239      * The update runs asynchronously and clients are notified via
240      * {@link AutoCommentChangeListener#elementUpdated}
241      * @param el
242      * @param doc
243      */

244     public void modifyJavadoc(final AutoCommenter.Element el, final JavaDoc doc) {
245         QUEUE.post(new Runnable JavaDoc() {
246             public void run() {
247                 try {
248                     JavaModel.getJavaRepository().beginTrans(true);
249                     try {
250                         if (el.getSrcElement().isValid()) {
251                             el.setJavaDoc(doc);
252                             el.checkError();
253                             fireElementUpdatedEvent(el);
254                         }
255                     } finally {
256                         JavaModel.getJavaRepository().endTrans();
257                     }
258                 } catch (JmiException e) {
259                     ErrorManager.getDefault().notify(e);
260                 }
261             }
262         });
263     }
264     
265     /**
266      * tries to auto correct javadoc of the <code>element</code>.
267      * The method runs asynchronously and clients are notified via
268      * {@link AutoCommentChangeListener#elementUpdated}
269      * @param element an elemnt to auto correct
270      * @param doc javadoc that should be applied before correction; can be
271      * <code>null</code>
272      */

273     public void autoCorrectJavadoc(final AutoCommenter.Element element, final JavaDoc doc) {
274         QUEUE.post(new Runnable JavaDoc() {
275             public void run() {
276                 try {
277                     JavaModel.getJavaRepository().beginTrans(true);
278                     try {
279                         if (element.getSrcElement().isValid()) {
280                             if (doc != null) {
281                                 element.setJavaDoc(doc);
282                             }
283                             element.autoCorrect();
284                             element.checkError();
285                             fireElementUpdatedEvent(element);
286                         }
287                     } finally {
288                         JavaModel.getJavaRepository().endTrans();
289                     }
290                 } catch (JmiException e) {
291                     ErrorManager.getDefault().notify(e);
292                 } catch (org.openide.src.SourceException e) {
293                     ErrorManager.getDefault().notify(e);
294                 }
295             }
296         });
297     }
298     
299     /**
300      * tries to auto correct javadoc of all <code>elements</code>.
301      * The method runs asynchronously and clients are notified via
302      * {@link AutoCommentChangeListener#listChanged}
303      * @param elements an array of elemnts to auto correct
304      */

305     public void autoCorrectJavadoc(final AutoCommenter.Element[] elements) {
306         if (elements == null) {
307             throw new NullPointerException JavaDoc("elements"); // NOI18N
308
}
309         QUEUE.post(new Runnable JavaDoc() {
310             public void run() {
311                 try {
312                     JavaModel.getJavaRepository().beginTrans(true);
313                     try {
314                         for (int i = 0; i < elements.length; i++) {
315                             Element element = elements[i];
316                             if (element.getSrcElement().isValid()) {
317                                 element.autoCorrect();
318                                 element.checkError();
319                             }
320                         }
321                         fireAutocommentChangeEvent();
322                     } finally {
323                         JavaModel.getJavaRepository().endTrans();
324                     }
325                 } catch (JmiException e) {
326                     ErrorManager.getDefault().notify(e);
327                 } catch (org.openide.src.SourceException e) {
328                     ErrorManager.getDefault().notify(e);
329                 }
330             }
331         });
332     }
333     
334     private void refreshFromSourceImpl() {
335         updateDataObjects();
336         List JavaDoc dobjs;
337         synchronized (this.dataObjects) {
338             dobjs = new ArrayList(this.dataObjects);
339         }
340         elements = new ArrayList(dobjs.size());
341         try {
342             JavaModel.getJavaRepository().beginTrans(false);
343             try {
344                 for (Iterator it = dobjs.iterator(); it.hasNext();) {
345                     DataObject d = (DataObject) it.next();
346                     Resource r = JavaModel.getResource(d.getPrimaryFile());
347                     if (r != null) {
348                         addCommentable(r);
349                     }
350                 }
351             } finally {
352                 JavaModel.getJavaRepository().endTrans();
353             }
354         } catch (JmiException ex) {
355             ErrorManager.getDefault().notify(ex);
356         }
357     }
358
359     private void addCommentable(Resource r){
360         List JavaDoc/*<JavaClass>*/ classes = JMIUtils.getAllClasses(r);
361         for (Iterator it = classes.iterator(); it.hasNext();) {
362             JavaClass jc = (JavaClass) it.next();
363             if (jc.isValid()) {
364                 addElements(jc);
365             }
366         }
367     }
368
369     private void prepareListModel( DefaultListModel listModel, int mask, boolean pckg, int err_mask ) {
370         for(Iterator it = elements.iterator(); it.hasNext(); ) {
371             Element el = (Element) it.next();
372
373             if ( acceptElement( el, mask, pckg, err_mask ) ) {
374                 listModel.addElement(el);
375             }
376         }
377     }
378
379     static boolean acceptElement( Element el, int mask, boolean pckg, int err_mask ) {
380
381         // Test whether the element is accepted by error mask
382

383         if ( ( el.getErrorNumber() & err_mask ) == 0 )
384             return false;
385
386         // Test whether the element is accepted by access mask
387
int access = el.getDescriptor().getEffectiveAccess();
388         if (access == 0)
389             return pckg;
390         else
391             return (access & mask) > 0;
392     }
393
394     DefaultListModel prepareListModel( int mask, boolean pckg, int err_mask ) {
395         DefaultListModel dm = new DefaultListModel();
396         prepareListModel( dm, mask, pckg, err_mask );
397         return dm;
398     }
399
400     private void addElements(JavaClass classElement ) {
401         elements.add(createAutoCommenterElement(classElement));
402
403         List JavaDoc features = classElement.getFeatures();
404         for (Iterator it = features.iterator(); it.hasNext();) {
405             Object JavaDoc feature = it.next();
406             if (feature instanceof JavaClass || !(feature instanceof ClassMember))
407                 continue;
408             Element el = createAutoCommenterElement((ClassMember) feature);
409             if (el != null)
410                 elements.add(el);
411         }
412     }
413     
414     /**
415      * factory method for AutoCommenter elements
416      * @param element resource member to comment
417      * @return commentable or null
418      */

419     public static Element createAutoCommenterElement(ClassMember element) {
420         Element jdElement = null;
421         if (element instanceof JavaClass) {
422             // class + interface + enum + ann type
423
jdElement = new Element.Class((JavaClass) element);
424         } else if (element instanceof org.netbeans.jmi.javamodel.Field) {
425             // field + enum constant
426
jdElement = new Element.Field((org.netbeans.jmi.javamodel.Field) element);
427         } else if (element instanceof org.netbeans.jmi.javamodel.Constructor) {
428             jdElement = new Element.Constructor((org.netbeans.jmi.javamodel.Constructor) element);
429         } else if (element instanceof org.netbeans.jmi.javamodel.Method) {
430             jdElement = new Element.Method((org.netbeans.jmi.javamodel.Method) element);
431         } else if (element instanceof Attribute) {
432             jdElement = new Element.Field((Attribute) element);
433         }
434         if (jdElement != null) {
435             jdElement.initialize();
436         }
437         return jdElement;
438     }
439     
440     /** innerclass holds the element and the informations about comment errors */
441
442     static abstract class Element {
443
444         private DefaultListModel errorList;
445
446         protected final ClassMember srcElement;
447         private int srcError = JDC_OK;
448             
449         private JavaDoc javadoc;
450         
451         private ElementDescriptor desc;
452         
453         private boolean isValid = true;
454
455         protected Element(ClassMember srcElement) {
456             this.srcElement = srcElement;
457         }
458         
459         /**
460          * initialize element properties for work inside the awt event queue;
461          * should be invoked just from the factory
462          * @throws JmiException
463          */

464         protected final void initialize() throws JmiException {
465             javadoc = createJavaDoc();
466             desc = new ElementDescriptor(this, getNameFormat());
467             checkError();
468         }
469         
470         public final boolean isValid() {
471             return isValid;
472         }
473         
474         /** needs to be run inside mdr transaction;
475          * clients should use this outside of the awt event queue.
476          */

477         public final ElementDescriptor getDescriptor() throws JmiException {
478             assert desc != null;
479             return desc;
480         }
481
482         public final ClassMember getSrcElement() {
483             return srcElement;
484         }
485
486         public final int getErrorNumber() {
487             return srcError;
488         }
489
490         public final void viewSource() {
491             AutoCommenter.QUEUE.post(new Runnable JavaDoc() {
492                 int state = 0;
493                 EditorCookie ec;
494                 int offset;
495                 DataObject dobj;
496                 
497                 public void run() {
498                     switch (state) {
499                         case 0:
500                             findOffset();
501                             break;
502                         case 1:
503                             open();
504                             break;
505                     }
506                 }
507                 
508                 void findOffset() {
509                     try {
510                         JavaModel.getJavaRepository().beginTrans(false);
511                         try {
512                             if (!srcElement.isValid()) return;
513                             
514                             Resource r = srcElement.getResource();
515                             if (r == null) return;
516                             offset = JavaMetamodel.getManager().
517                                                 getElementPosition(srcElement).getBegin().getOffset();
518                             dobj = JavaMetamodel.getManager().getDataObject(r);
519                             if (dobj == null) return;
520                             ec = (EditorCookie) dobj.getCookie(EditorCookie.class);
521                             if (ec == null) return;
522                             ++state;
523                             EventQueue.invokeLater(this);
524                         } finally {
525                             JavaModel.getJavaRepository().endTrans();
526                         }
527                     } catch (JmiException e) {
528                         ErrorManager.getDefault().notify(e);
529                         return;
530                     }
531                 }
532             
533                 void open() {
534                     ec.open();
535                     JEditorPane[] epane = ec.getOpenedPanes();
536                     if (epane != null && epane.length > 0) {
537                         epane[0].getCaret().setDot(offset);
538                         epane[0].requestFocus();
539                     }
540                 }
541             });
542         }
543
544         public synchronized final DefaultListModel getErrorList() {
545             return errorList;
546         }
547
548         protected abstract String JavaDoc[] getNotPermittedTags();
549
550         /**
551          * check if javadoc tags are valid.
552          * implementor should use descriptor instead of jmi element
553          * @return
554          */

555         protected abstract boolean elementTagsOk(DefaultListModel errList);
556         
557         /**
558          * needs MDR transaction
559          * @throws SourceException
560          */

561         public abstract void autoCorrect() throws SourceException;
562
563         protected abstract JavaDoc createJavaDoc();
564         
565         public final JavaDoc getJavaDoc() {
566             assert javadoc != null;
567             return javadoc;
568         }
569         
570         /**
571          * set new javadoc; needs mdr transaction
572          * @param doc new javadoc
573          * @throws JmiException
574          */

575         public final void setJavaDoc(final JavaDoc doc) throws JmiException {
576             if (doc == null) throw new NullPointerException JavaDoc("doc"); // NOI18N
577

578             this.srcElement.setJavadocText(doc.getRawText());
579             this.javadoc = createJavaDoc();
580         }
581
582         protected abstract Format JavaDoc getNameFormat();
583
584         protected abstract String JavaDoc typeToString();
585
586         static boolean isPermittedTag(JavaDocTag tag, String JavaDoc[] notPermittedTags ) {
587             String JavaDoc tagName = tag.name();
588
589             for ( int i = 0; i < notPermittedTags.length; i++ ) {
590                 if ( tagName.equals( notPermittedTags[i] ) )
591                     return false;
592             }
593
594             return true;
595         }
596
597         private static boolean isEmptyString( String JavaDoc string ) {
598             return string == null || string.trim().length() <= 0;
599         }
600
601         /** Checks syntax of the tags
602          */

603
604         private boolean isOkTag(JavaDocTag tag, DefaultListModel errList ) {
605             if ( isEmptyString( tag.text() ) ) {
606                 log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_EmptyTag" ), //NOI18N
607
new Object JavaDoc[] { tag.name() } ) );
608                 return false;
609             }
610
611             if ( tag instanceof JavaDocTag.See ) {
612                 int len;
613                 String JavaDoc text;
614                 JavaDocTag.See seetag = (JavaDocTag.See) tag;
615                 
616                 if ((seetag.referencedClassName() != null) || (seetag.referencedMemberName() != null))
617                     return true;
618                 text=tag.text();
619                 len = text.length();
620                 if (len >= 2) {
621                     char first=text.charAt(0);
622                     char last=text.charAt(len-1);
623                     
624                     if (first=='"' && last==first)
625                         return true;
626                     if (first=='<' && last=='>')
627                         return true;
628                 }
629                 log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_InvalidTag" ), //NOI18N
630
new Object JavaDoc[] { seetag } )); //NOI18N
631
return false;
632             }
633             else if ( tag instanceof JavaDocTag.Param ) {
634                 if ( isEmptyString( ((JavaDocTag.Param)tag).parameterName() ) ) {
635                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ParamNoName" ), //NOI18N
636
new Object JavaDoc[] { tag.name() } ) );
637                     return false;
638                 }
639                 if ( isEmptyString( ((JavaDocTag.Param)tag).parameterComment() ) ) {
640                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ParamNoDescr" ), //NOI18N
641
new Object JavaDoc[] { tag.name(), ((JavaDocTag.Param)tag).parameterName() } ) );
642                     return false;
643                 }
644             }
645             else if ( tag instanceof JavaDocTag.Throws ) {
646                 if ( isEmptyString( ((JavaDocTag.Throws)tag).exceptionName() ) ) {
647                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ThrowsNoName" ), //NOI18N
648
new Object JavaDoc[] { tag.name() } ) );
649                     return false;
650                 }
651                 if ( isEmptyString( ((JavaDocTag.Throws)tag).exceptionComment() ) ) {
652                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_ThrowsNoDescr" ), //NOI18N
653
new Object JavaDoc[] { tag.name(), ((JavaDocTag.Throws)tag).exceptionName() } ) );
654                     return false;
655                 }
656             }
657             else if ( tag instanceof JavaDocTag.SerialField ) {
658                 if ( isEmptyString( ((JavaDocTag.SerialField)tag).fieldName() ) ) {
659                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_SerialFieldNoName" ), //NOI18N
660
new Object JavaDoc[] { tag.name() } ) );
661                     return false;
662                 }
663                 if ( isEmptyString( ((JavaDocTag.SerialField)tag).fieldType() ) ) {
664                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_SerialFieldNoType" ), //NOI18N
665
new Object JavaDoc[] { tag.name(), ((JavaDocTag.SerialField)tag).fieldName() } ) );
666                     return false;
667                 }
668
669                 if ( isEmptyString( ((JavaDocTag.SerialField)tag).description() ) ) {
670                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_SerialFieldNoDescr" ), //NOI18N
671
new Object JavaDoc[] { tag.name(), ((JavaDocTag.SerialField)tag).fieldName() } ) );
672                     return false;
673                 }
674             }
675             return true;
676         }
677
678         protected final boolean isMultipleTags(String JavaDoc tag, DefaultListModel errList) {
679             // Check for multiple tags
680
boolean error = false;
681             JavaDocTag[] tags = getJavaDoc().getTags(tag);
682             if ( tags.length > 1) {
683                 log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_DuplicatedTag" ), //NOI18N
684
new Object JavaDoc[] { tags[0].name() } ) );
685                 error = true;
686             }
687             return error;
688         }
689         
690         /**
691          * check current javadoc.
692          */

693         public final void checkError() {
694             
695             DefaultListModel _errorList = new DefaultListModel();
696
697             JavaDoc jdoc = getJavaDoc();
698
699             if ( jdoc.isEmpty() ) {
700                 _errorList.addElement( ResourceUtils.getBundledString( "ERR_JavadocMissing" ) ); //NOI18N
701
synchronized(this) {
702                     srcError = JDC_MISSING;
703                     this.errorList = _errorList;
704                 }
705                 desc.recomputeIcon();
706                 return;
707             }
708
709             JavaDocTag[] tags = jdoc.getTags();
710             boolean error = false;
711
712             if ( jdoc.getText() == null || jdoc.getText().trim().length() <= 0 ) {
713                 _errorList.addElement( ResourceUtils.getBundledString( "ERR_EmptyText" ) ); //NOI18N
714
error = true;
715             }
716
717             for ( int i = 0; i < tags.length; i ++ ) {
718                 if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) {
719                     _errorList.addElement( MessageFormat.format( ResourceUtils.getBundledString( "ERR_BadTag" ), //NOI18N
720
new Object JavaDoc[] { tags[i].name(), typeToString() } ) );
721                     error = true;
722                     continue;
723                 }
724
725                 if (!isOkTag(tags[i], _errorList)) {
726                     error = true;
727                     continue;
728                 }
729             }
730             
731             if (isMultipleTags(TAG_SINCE, _errorList)) {
732                 error = true;
733             }
734             
735             if (isMultipleTags(TAG_DEPRECATED, _errorList)) {
736                 error = true;
737             }
738             
739             if (!elementTagsOk(_errorList)) {
740                 error = true;
741             }
742
743             if ( !error ) {
744                 _errorList.addElement( ResourceUtils.getBundledString( "ERR_JavadocOK" ) ); //NOI18N
745
}
746
747             synchronized (this) {
748                 srcError = error ? JDC_ERROR : JDC_OK;
749                 this.errorList = _errorList;
750             }
751             desc.recomputeIcon();
752         }
753         
754         /**
755          * check if javadoc needs some correction; implementors should use
756          * descriptor instead of jmi calls
757          * @return
758          */

759         public boolean isCorrectable() {
760             assert this.javadoc != null;
761             assert this.desc != null;
762             JavaDocTag[] tags = getJavaDoc().getTags();
763
764             for ( int i = 0; i < tags.length; i ++ ) {
765                 if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) {
766                     return true;
767                 }
768             }
769
770             return false;
771         }
772
773         /**
774          * needs mdr transaction
775          * @param jdoc
776          * @throws SourceException
777          */

778         protected void autoCorrect( JavaDoc jdoc ) throws SourceException {
779             JavaDocTag[] tags = jdoc.getTags();
780             ArrayList correctedTags = new ArrayList( tags.length );
781             String JavaDoc correctedText;
782
783             correctedText = jdoc.getText();
784
785             if ( correctedText == null ) {
786                 correctedText = ""; // NOI18N
787
}
788
789             for ( int i = 0; i < tags.length; i ++ ) {
790                 if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) {
791                     continue;
792                 }
793                 correctedTags.add( tags[i] );
794             }
795
796             jdoc.changeTags( (JavaDocTag[])correctedTags.toArray( new JavaDocTag[ correctedTags.size() ] ), JavaDoc.SET );
797         }
798         
799         private static void log(DefaultListModel errList, String JavaDoc txt) {
800             if (errList != null) {
801                 errList.addElement(txt);
802             }
803         }
804
805         public boolean equals(Object JavaDoc o) {
806             if (this == o) return true;
807             if (!(o instanceof Element)) return false;
808
809             final Element element = (Element) o;
810
811             if (desc != null && element.desc != null && desc.getIdentity().equals(element.desc.getIdentity())) {
812                 return true;
813             }
814
815             return false;
816         }
817
818         public int hashCode() {
819             return (desc != null ? desc.getIdentity().hashCode() : 0);
820         }
821
822
823         static class Class extends Element {
824
825             private static final String JavaDoc[] NOT_PERMITTED_TAGS = {
826                 TAG_EXCEPTION,
827                 TAG_PARAM,
828                 TAG_RETURN,
829                 TAG_SERIAL,
830                 TAG_SERIALDATA,
831                 TAG_SERIALFIELD,
832                 TAG_THROWS,
833             };
834
835             private static final Format JavaDoc nameFormat = SourceNodes.createElementFormat("{C}"); // NOI18N
836

837             protected Class( JavaClass element ) {
838                 super( element );
839             }
840
841             public String JavaDoc[] getNotPermittedTags() {
842                 return NOT_PERMITTED_TAGS;
843             }
844             
845             protected boolean elementTagsOk(DefaultListModel errList) {
846                 boolean error = false;
847                 if (this.isMultipleTags(TAG_VERSION, errList)) {
848                     error = true;
849                 }
850                 return !error;
851             }
852
853             public void autoCorrect() throws SourceException {
854                 super.autoCorrect( getJavaDoc() );
855                 setJavaDoc(getJavaDoc());
856             }
857
858             public String JavaDoc typeToString() {
859                 String JavaDoc type;
860                 if (this.srcElement instanceof JavaEnum) {
861                     type = "enum"; // NOI18N
862
} else if (this.srcElement instanceof AnnotationType) {
863                     type = "annotation type"; // NOI18N
864
} else {
865                     type = Modifier.isInterface(getDescriptor().getModifiers())
866                             ? "interface" : "class"; // NOI18N
867
}
868                 return type;
869             }
870
871             protected JavaDoc createJavaDoc() {
872                 String JavaDoc s = srcElement.getJavadocText();
873                 JavaDoc javadoc = JavaDocSupport.createClassJavaDoc(s);
874                 return javadoc;
875             }
876
877             public Format JavaDoc getNameFormat () {
878                 return nameFormat;
879             }
880
881         }
882
883         static class Field extends Element {
884
885             private static final String JavaDoc[] NOT_PERMITTED_TAGS = {
886                 TAG_AUTHOR,
887                 TAG_EXCEPTION,
888                 TAG_PARAM,
889                 TAG_RETURN,
890                 TAG_SERIALDATA,
891                 TAG_THROWS,
892                 TAG_VERSION
893             };
894
895             private static final Format JavaDoc nameFormat = SourceNodes.createElementFormat("{n}"); // NOI18N
896

897             protected Field(org.netbeans.jmi.javamodel.Field element ) {
898                 super( element );
899             }
900             
901             protected Field(Attribute element ) {
902                 super( element );
903             }
904             
905             protected JavaDoc createJavaDoc() {
906                 String JavaDoc s = srcElement.getJavadocText();
907                 JavaDoc javaDoc = JavaDocSupport.createFieldJavaDoc(s);
908                 return javaDoc;
909             }
910
911             public String JavaDoc[] getNotPermittedTags() {
912                 return NOT_PERMITTED_TAGS;
913             }
914
915             public String JavaDoc typeToString() {
916                 return this.srcElement instanceof Field? "field": "attribute"; // NOI18N
917
}
918
919             protected boolean elementTagsOk(DefaultListModel errList) {
920                 boolean error = false;
921                 if (this.isMultipleTags(TAG_SERIAL, errList)) {
922                     error = true;
923                 }
924                 
925                 return !error;
926             }
927
928             public void autoCorrect() throws SourceException {
929                 super.autoCorrect( getJavaDoc() );
930                 setJavaDoc(getJavaDoc());
931             }
932
933             public Format JavaDoc getNameFormat () {
934                 return nameFormat;
935             }
936         }
937
938         static class Constructor extends Element {
939
940             private static final String JavaDoc[] NOT_PERMITTED_TAGS = {
941                 TAG_AUTHOR,
942                 TAG_SERIAL,
943                 TAG_SERIALFIELD,
944                 TAG_VERSION,
945                 TAG_RETURN
946             };
947
948             private static final Format JavaDoc nameFormat = SourceNodes.createElementFormat("{n}({p,,,\",\"})"); // NOI18N
949

950             protected Constructor(org.netbeans.jmi.javamodel.CallableFeature element) {
951                 super( element );
952             }
953             
954             protected JavaDoc createJavaDoc() {
955                 String JavaDoc s = srcElement.getJavadocText();
956                 JavaDoc javadoc = JavaDocSupport.createMethodJavaDoc(s);
957                 return javadoc;
958             }
959
960             public String JavaDoc[] getNotPermittedTags() {
961                 return NOT_PERMITTED_TAGS;
962             }
963
964             public String JavaDoc typeToString() {
965                 return "constructor"; // NOI18N
966
}
967
968             protected boolean elementTagsOk(DefaultListModel errList) {
969                 return elementTagsOk( null, false, errList );
970             }
971
972             private boolean elementTagsOk( ArrayList correctedTags, boolean checkOnly, DefaultListModel errList ) {
973
974                 boolean error = false;
975
976                 // Check param tags
977

978                 JavaDoc jdoc = getJavaDoc();
979                 JavaDocTag.Param[] ptags = ((JavaDoc.Method) jdoc).getParamTags();
980                 boolean[] ptags_found = new boolean[ ptags.length ];
981                 
982                 // Check if all parameters for the method are in the javadoc
983
// and if there are any parameter tag duplicates.
984
String JavaDoc[] params = getDescriptor().getParameterNames();
985                 for (int j = 0; j < params.length; j++) {
986                     String JavaDoc param = params[j];
987                     boolean tagFound = false;
988                     boolean duplicateTagAlreadyFound = false;
989                     for (int i = 0 ; i < ptags.length ; i++) {
990                         if (ptags[i].parameterName() != null && ptags[i].parameterName().equals(param)) {
991                             ptags_found[i] = true;
992                             if (!tagFound) {
993                                 tagFound = true;
994                             } else if (! duplicateTagAlreadyFound) {
995                                 if ( checkOnly ) {
996                                     return false;
997                                 } else if ( correctedTags == null ) {
998                                     log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_DuplicatedParamTag" ), //NOI18N
999
new Object JavaDoc[] { param } ) );
1000                                }
1001                                error = true;
1002                                duplicateTagAlreadyFound = true;
1003                            }
1004                        }
1005                    }
1006                        
1007                    if (! tagFound ) {
1008                        if ( checkOnly ) {
1009                            return false;
1010                        } else if ( correctedTags == null ) {
1011                            error = true;
1012                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoTagForParam" ), //NOI18N
1013
new Object JavaDoc[] { param } ) );
1014                        }
1015                        else {
1016                            correctedTags.add( JavaDocSupport.createParamTag( TAG_PARAM, param ) );
1017                        }
1018                    }
1019                }
1020                        
1021                for( int i = 0; i < ptags.length; i++ ) {
1022                    if ( !ptags_found[i] ) {
1023                        if ( checkOnly ) {
1024                            return false;
1025                        }
1026                        else if ( correctedTags == null ) {
1027                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoSuchParam" ), //NOI18N
1028
new Object JavaDoc[] { ptags[i].name(), ptags[i].parameterName() } ) );
1029                        }
1030                        error = true;
1031                    }
1032                    else if ( correctedTags != null ) {
1033                        correctedTags.add( ptags[i] );
1034                    }
1035
1036
1037                }
1038                // Check throws tags
1039

1040
1041                JavaDocTag.Throws[] ttags = ((JavaDoc.Method) getJavaDoc()).getThrowsTags();
1042                boolean[] ttags_found = new boolean[ ttags.length ];
1043                String JavaDoc[] excs = getDescriptor().getThrowFQNames();
1044
1045                // Check if all exceptions for the method are in the javadoc
1046
// and if there are any exception tag duplicates.
1047
for (int j = 0; j < excs.length; j++) {
1048                    String JavaDoc excFQN = excs[j];
1049                    boolean tagFound = false;
1050                    boolean duplicateTagAlreadyFound = false;
1051                    for (int i = 0 ; i < ttags.length ; i++) {
1052                        //<workaround id=#36447>
1053
String JavaDoc tagExId = ttags[i].exceptionName().replaceFirst("\\.+\\z", ""); // NOI18N
1054
//</workaround>
1055

1056                        
1057                        if (tagExId.length() > 0 && excFQN.endsWith(tagExId)) {
1058                            ttags_found[i] = true;
1059                            if (!tagFound) {
1060                                tagFound = true;
1061                            } else if (! duplicateTagAlreadyFound){
1062                                if ( checkOnly ) {
1063                                    return false;
1064                                }
1065                                else if ( correctedTags == null ) {
1066                                    log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_DuplicatedExceptionTag" ), //NOI18N
1067
new Object JavaDoc[] { excFQN }));
1068                                }
1069                                error = true;
1070                                duplicateTagAlreadyFound = true;
1071                            }
1072                        }
1073                    }
1074                        
1075                    if (! tagFound ) {
1076                        if ( checkOnly ) {
1077                            return false;
1078                        } else if ( correctedTags == null ) {
1079                            error = true;
1080                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoTagForException" ), //NOI18N
1081
new Object JavaDoc[] { excFQN }));
1082                        }
1083                        else {
1084                            correctedTags.add( JavaDocSupport.createThrowsTag( TAG_THROWS, excFQN));
1085                        }
1086                    }
1087                }
1088                        
1089                for( int i = 0; i < ttags.length; i++ ) {
1090                    if ( !ttags_found[i] ) {
1091                        if ( checkOnly ) {
1092                            return false;
1093                        }
1094                        else if ( correctedTags == null ) {
1095                            log(errList, MessageFormat.format( ResourceUtils.getBundledString( "ERR_NoSuchException" ), //NOI18N
1096
new Object JavaDoc[] { ttags[i].name(), ttags[i].exceptionName() } ) );
1097                        }
1098                        error = true;
1099                    }
1100                    else if ( correctedTags != null ) {
1101                        correctedTags.add( ttags[i] );
1102                    }
1103
1104
1105                }
1106
1107                return !error;
1108            }
1109
1110            public boolean isCorrectable () {
1111                if ( super.isCorrectable() )
1112                    return true;
1113
1114                return !elementTagsOk( null, true, null );
1115            }
1116
1117            public void autoCorrect() throws SourceException {
1118                autoCorrect(getJavaDoc());
1119                setJavaDoc(getJavaDoc());
1120            }
1121
1122            public void autoCorrect( JavaDoc jDoc ) throws SourceException {
1123                JavaDoc.Method jdTemp = JavaDocSupport.createMethodJavaDoc(getJavaDoc().getRawText());
1124
1125                // create comment without throws and params
1126

1127                JavaDocTag tags[] = jdTemp.getTags();
1128                ArrayList stdTags = new ArrayList( tags.length );
1129
1130                for( int i = 0; i < tags.length; i++ ) {
1131                    if ( !( tags[i] instanceof JavaDocTag.Param ) &&
1132                            !( tags[i] instanceof JavaDocTag.Throws ) ) {
1133                        stdTags.add( tags[i] );
1134                    }
1135                }
1136
1137                jdTemp.changeTags( (JavaDocTag[])stdTags.toArray( new JavaDocTag[ stdTags.size() ] ), JavaDoc.SET );
1138
1139                super.autoCorrect( jdTemp );
1140
1141                ArrayList correctedTags = new ArrayList();
1142                elementTagsOk( correctedTags, false, null );
1143
1144                // Build all tags collection
1145

1146                ArrayList allTags = new ArrayList( correctedTags.size() + tags.length );
1147                tags = jdTemp.getTags();
1148                for( int i = 0; i < tags.length; i++ ) {
1149                    allTags.add( tags[i] );
1150                }
1151                allTags.addAll( correctedTags );
1152
1153                jDoc.changeTags( (JavaDocTag[])allTags.toArray( new JavaDocTag[ allTags.size() ] ), JavaDoc.SET );
1154            }
1155
1156            public Format JavaDoc getNameFormat () {
1157                return nameFormat;
1158            }
1159
1160        }
1161
1162        static class Method extends Constructor {
1163
1164            private static final Format JavaDoc nameFormat = SourceNodes.createElementFormat("{n}({p,,,\",\"})"); // NOI18N
1165

1166            private static final String JavaDoc[] NOT_PERMITTED_TAGS = {
1167                TAG_AUTHOR,
1168                TAG_SERIAL,
1169                TAG_SERIALFIELD,
1170                TAG_VERSION
1171            };
1172            
1173            Method(org.netbeans.jmi.javamodel.Method element) {
1174                super( element );
1175            }
1176
1177            public String JavaDoc typeToString() {
1178                return "method"; // NOI18N
1179
}
1180
1181            public String JavaDoc[] getNotPermittedTags() {
1182                return NOT_PERMITTED_TAGS;
1183            }
1184
1185            protected boolean elementTagsOk(DefaultListModel errList) {
1186                boolean superOk = super.elementTagsOk(errList);
1187                boolean retOk = checkReturnType(false, errList);
1188                return !superOk ? false : retOk;
1189            }
1190
1191            private boolean checkReturnType(boolean checkOnly, DefaultListModel errList) {
1192
1193                boolean retOk = true;
1194
1195                String JavaDoc retFQN = getDescriptor().getTypeFQName();
1196                JavaDocTag[] retTags = getJavaDoc().getTags(TAG_RETURN);
1197                
1198                boolean isVoid = "void".equals(retFQN); // NOI18N
1199

1200                if (isVoid && retTags.length > 0) {
1201                    if ( checkOnly ) {
1202                        return false;
1203                    }
1204                    log(errList, ResourceUtils.getBundledString( "ERR_ReturnForVoid" ) ); //NOI18N
1205
retOk = false;
1206                } else if (!isVoid && retTags.length <= 0) {
1207                    if ( checkOnly ) {
1208                        return false;
1209                    }
1210                    log(errList, ResourceUtils.getBundledString( "ERR_NoReturn" ) ); //NOI18N
1211
retOk = false;
1212                } else if (!isVoid && retTags.length > 1) {
1213                    if ( checkOnly) {
1214                        return false;
1215                    }
1216                    log(errList, ResourceUtils.getBundledString( "ERR_DuplicatedReturn" ) ); //NOI18N
1217
retOk = false;
1218                }
1219
1220                return retOk;
1221            }
1222
1223            public boolean isCorrectable() {
1224
1225                if ( super.isCorrectable() )
1226                    return true;
1227
1228                return !checkReturnType(true, null);
1229            }
1230
1231            public void autoCorrect() throws SourceException {
1232                JavaDoc jdTemp = JavaDocSupport.createMethodJavaDoc( getJavaDoc().getRawText() );
1233                super.autoCorrect( jdTemp );
1234
1235                if (!checkReturnType(true, null) ) {
1236                    String JavaDoc retFQN = getDescriptor().getTypeFQName();
1237                    if (!"void".equals(retFQN)) { // NOI18N
1238
jdTemp.changeTags(
1239                            new JavaDocTag[] { JavaDocSupport.createTag( TAG_RETURN, "" ) }, // NOI18N
1240
JavaDoc.ADD );
1241                    } else {
1242                        JavaDocTag toRemove[] = jdTemp.getTags( TAG_RETURN );
1243
1244                        jdTemp.changeTags( toRemove, JavaDoc.REMOVE );
1245                    }
1246                }
1247
1248                getJavaDoc().setRawText( jdTemp.getRawText() );
1249                setJavaDoc(getJavaDoc());
1250            }
1251
1252            public Format JavaDoc getNameFormat () {
1253                return nameFormat;
1254            }
1255        }
1256    }
1257
1258    public interface AutoCommentChangeListener extends EventListener {
1259        /**
1260         * notifies that auto commenter computed new list of commantable elements.
1261         */

1262        public void listChanged();
1263        /**
1264         * notifies about element's javadoc update
1265         * @param el
1266         */

1267        public void elementUpdated(AutoCommenter.Element el);
1268    }
1269    
1270    /** Registers PropertyChangeListener to receive events.
1271     * @param listener The listener to register.
1272     */

1273    public synchronized void addAutoCommentChangeListener(AutoCommentChangeListener listener) throws java.util.TooManyListenersException JavaDoc {
1274        if (autoCommentChangeListener != null) {
1275            throw new java.util.TooManyListenersException JavaDoc();
1276        }
1277        autoCommentChangeListener = listener;
1278    }
1279    
1280    /** Removes PropertyChangeListener from the list of listeners.
1281     * @param listener The listener to remove.
1282     */

1283    public synchronized void removeAutoCommentChangeListener(AutoCommentChangeListener listener) {
1284        autoCommentChangeListener = null;
1285    }
1286    
1287    /** Notifies the registered listener about the event.
1288     */

1289    private void fireAutocommentChangeEvent() {
1290        if (autoCommentChangeListener == null) return;
1291        autoCommentChangeListener.listChanged();
1292    }
1293    
1294    private void fireElementUpdatedEvent(AutoCommenter.Element el) {
1295        if (autoCommentChangeListener == null) return;
1296        autoCommentChangeListener.elementUpdated(el);
1297    }
1298}
1299
Popular Tags