KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > src > ClassElement


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.openide.src;
21
22 import java.util.*;
23 import java.lang.reflect.Modifier JavaDoc;
24
25
26 import org.openide.filesystems.FileObject;
27 import org.openide.util.NbBundle;
28
29 /** Element that describes one class.
30 * Note that this is a member element--in fact, it may be either a
31 * top-level class (held in a source element), or a named inner class
32 * (held in another class element).<P>
33 * <B>Note:</B> If you add an element to a ClassElement, the ClassElement
34 * crates its own copy of the passed element. If you perform subsequent
35 * modifications to the object passed to addMethod (addField, addWhatever),
36 * the original element will be updated, <B>not</B> the one created as a result
37 * of the add() operation.
38 *
39 * @author Petr Hamernik, Jaroslav Tulach
40 */

41 public final class ClassElement extends MemberElement {
42     /** Constant indicating that the class is a real class.
43     * @see #isClassOrInterface
44     */

45     public static final boolean CLASS = true;
46
47     /** Constant indicating that the class is an interface.
48     * @see #isClassOrInterface
49     */

50     public static final boolean INTERFACE = false;
51
52     /** Default class to extend.
53     * That is, <code>Object</code>.
54     */

55     public static final Identifier ROOT_OBJECT = Identifier.create("java.lang.Object", "Object"); // NOI18N
56

57     /** Formats for the header - used in code generator */
58     private static final ElementFormat HEADER_FORMAT[] = {
59         new ElementFormat("{m,,\" \"}class {n}{s,\" extends \",}{i,\" implements \",}"), // NOI18N
60
new ElementFormat("{m,,\" \"}interface {n}{i,\" extends \",}") // NOI18N
61
};
62
63     /** source element we are attached to */
64     private SourceElement source;
65
66     //================ Constructors of ClassElement =================
67

68     static final long serialVersionUID =1692944638104452533L;
69
70     /** Create a new class element in memory.
71     */

72     public ClassElement() {
73         this(new Memory (), null, null);
74     }
75
76     /** Factory constructor for defining embedded classes.
77     *
78     * @param impl implementation of functionality
79     * @param clazz the declaring class, or <code>null</code>
80     */

81     public ClassElement(Impl impl, ClassElement clazz) {
82         this (impl, clazz, clazz.getSource ());
83     }
84
85     /** Factory constructor for defining top level classes.
86     * @param impl implementation of functionality
87     * @param source the source file this class is contained in, or <code>null</code>
88     */

89     public ClassElement(Impl impl, SourceElement source) {
90         this (impl, null, source);
91     }
92
93     /**
94     * @param impl implementation of functionality
95     * @param clazz the declaring class
96     * @param source the source file to be presented in
97     */

98     private ClassElement(Impl impl, ClassElement clazz, SourceElement source) {
99         super (impl, clazz);
100         this.source = source;
101     }
102
103     /** Clone this element.
104     * @return new element with the same values as the original,
105     * but represented in memory
106     */

107     public Object JavaDoc clone () {
108         Memory mem = new Memory (this);
109         ClassElement el = new ClassElement (mem, null, null);
110         mem.copyFrom (this);
111         return el;
112     }
113
114     /** @return implemetation factory for this class
115     */

116     final Impl getClassImpl () {
117         return (Impl)impl;
118     }
119
120     /** Implemented in ClassElement - update names of the constructors.
121     */

122     void updateConstructorsNames(Identifier name) throws SourceException {
123         ConstructorElement[] c = getConstructors();
124         Identifier constrName = Identifier.create(name.getName());
125         for (int i = 0; i < c.length; i++)
126             c[i].setName(constrName);
127         ClassElement[] classes = getClasses();
128         String JavaDoc prefix = getName().getFullName() + "."; // NOI18N
129
for (int i = 0; i < classes.length; i++) {
130             String JavaDoc simpleName = classes[i].getName().getName();
131             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(prefix);
132             sb.append(simpleName);
133             Identifier id = Identifier.create(sb.toString(), simpleName);
134             classes[i].setName(id);
135         }
136     }
137
138     //================ Main properties ==============================
139

140     /** Get the source element of this class.
141     * @return the source, or <code>null</code> if the class is not attached to any source
142     */

143     public SourceElement getSource () {
144         return source;
145     }
146
147     /** Set whether this is really a class, or an interface.
148     * @param isClass one of {@link #CLASS} or {@link #INTERFACE}
149     * @throws SourceException if impossible
150     */

151     public void setClassOrInterface(boolean isClass) throws SourceException {
152         getClassImpl ().setClassOrInterface (isClass);
153     }
154
155     /** Test whether this is really a class, or an interface.
156     * @return one of {@link #CLASS} or {@link #INTERFACE}
157     */

158     public boolean isClassOrInterface() {
159         return getClassImpl ().isClassOrInterface ();
160     }
161
162     /** Test whether this is really a class.
163     * @return <code>true</code> if so
164     * @see #isClassOrInterface
165     */

166     public boolean isClass() {
167         return getClassImpl ().isClassOrInterface ();
168     }
169
170     /** Test whether this is an interface.
171     * @return <code>true</code> if so
172     * @see #isClassOrInterface
173     */

174     public boolean isInterface() {
175         return !getClassImpl ().isClassOrInterface ();
176     }
177
178     /** Test if this is an inner class.
179     * If so, it has a declaring class.
180     * @return <code>true</code> if so
181     * @see #ClassElement(ClassElement.Impl, ClassElement)
182     */

183     public boolean isInner() {
184         return (getDeclaringClass() != null);
185     }
186
187     /* Get the modifiers of the class.
188     * @return the mask of possible modifiers for this element
189     * @see Modifier
190     */

191     public int getModifiersMask() {
192         int ret = Modifier.PUBLIC | Modifier.ABSTRACT;
193
194         if (isClass()) {
195             ret |= Modifier.FINAL;
196         }
197
198         if (isInner()) {
199             ret |= Modifier.PROTECTED | Modifier.PRIVATE |
200                    Modifier.STATIC;
201         }
202         return ret;
203     }
204
205     /** Set the name of this member. When naming an inner class, use dots instead
206     * dollar signs to separate inner class' name from outer class' one - $ is a valid
207     * character in an identifier. If you pass an Identifier with FQN "Foo$Bar",
208     * you will in fact create a ClassElement, which represents a top-level class named "Foo$Bar"
209     * instead of inner class "Bar" nested in top-level class "Foo"
210     * @param name the name
211     * @throws SourceException if impossible
212     */

213     public final void setName(Identifier name) throws SourceException {
214         String JavaDoc sn = name.getName();
215         String JavaDoc fn = name.getFullName();
216         if (!name.getSourceName().equals(sn)) {
217             // source name is not a simple name, in fact. Create a new identifier,
218
// which is well-formed.
219
name = Identifier.create(fn, sn);
220         }
221         ClassElement c = getDeclaringClass();
222         String JavaDoc msg = null;
223         if (c != null) {
224             ClassElement c1 = c.getClass(name);
225             if ((c1 != null) && (c1 != this)) {
226         msg = NbBundle.getMessage(ElementFormat.class,
227             "FMT_EXC_RenameClass", c.getName().getName(), name); // NOI18N
228
}
229         }
230         else {
231             if (source != null) {
232                 ClassElement c1 = source.getClass(name);
233                 if ((c1 != null) && (c1 != this)) {
234             msg = NbBundle.getMessage(ElementFormat.class,
235                 "FMT_EXC_RenameClassInSource", name); // NOI18N
236
}
237             }
238         }
239         if (msg != null) {
240         throwSourceException(msg);
241         }
242         super.setName(name);
243     }
244
245     /** Returns the signature of the class as used internally
246      * in the JVM. Any . are replaced by forward slashes as required by the
247      * VM specs.
248      * @return signature of the class.
249      */

250     public final String JavaDoc getSignature() {
251         return getVMName().replace('.', '/');
252     }
253
254     /** Creates a name of the class usable in the JVM.
255      * The method returns a fully qualified name of the class in a form accepted directly by the Java VM,
256      * usable for example in java.lang.Class.forName(). This differs from ClassElement.getName().getFullName() in that
257      * inner class names are separated by '$' rather than by '.'
258      * @return JVM-compatible fully qualified class name.
259      */

260     public final String JavaDoc getVMName() {
261     Identifier n = getName();
262     if (!isInner()) {
263         return n.getFullName();
264     }
265
266     StringBuffer JavaDoc sb = new StringBuffer JavaDoc(n.getFullName());
267     ClassElement c = this;
268     int index = sb.length();
269
270     while (true) {
271         index -= n.getSourceName().length() + 1;
272         sb.setCharAt(index, '$');
273         c = c.getDeclaringClass();
274             if (!c.isInner())
275                 break;
276             n = c.getName();
277     }
278     return sb.toString();
279     }
280
281     // ================= Super class =======================
282

283     /** Set the superclass of this class.
284     * @param superClass the superclass
285     * @throws SourceException if that is impossible
286     */

287     public void setSuperclass(Identifier superClass) throws SourceException {
288         getClassImpl ().setSuperclass (superClass);
289     }
290
291     /** Get the superclass of this class.
292     * @return superclass identifier, or <code>null</code> (for interfaces, or possibly for classes with superclass <code>Object</code>)
293     */

294     public Identifier getSuperclass() {
295         return getClassImpl ().getSuperclass ();
296     }
297
298     // ================= Initializers ========================
299

300     /** Add a new initializer block to this class.
301     * @param el the block to add
302     * @throws SourceException if impossible
303     */

304     public void addInitializer (InitializerElement el) throws SourceException {
305         getClassImpl ().changeInitializers (
306             new InitializerElement[] { el }, Impl.ADD
307         );
308     }
309
310     /** Add some initializer blocks to this class.
311     * @param els the blocks to add
312     * @throws SourceException if impossible
313     */

314     public void addInitializers (final InitializerElement[] els) throws SourceException {
315         getClassImpl ().changeInitializers (els, Impl.ADD);
316     }
317
318     /** Remove an initializer block from this class.
319     * @param el the block to remove
320     * @throws SourceException if impossible
321     */

322     public void removeInitializer (InitializerElement el) throws SourceException {
323         getClassImpl ().changeInitializers (
324             new InitializerElement[] { el }, Impl.REMOVE
325         );
326     }
327
328     /** Remove some initializer blocks from this class.
329     * @param els the blocks to remove
330     * @throws SourceException if impossible
331     */

332     public void removeInitializers (final InitializerElement[] els) throws SourceException {
333         getClassImpl ().changeInitializers (els, Impl.REMOVE);
334     }
335
336     /** Set the initializer blocks for this class.
337     * Any previous ones are just removed.
338     * @param els the new blocks
339     * @throws SourceException if impossible
340     */

341     public void setInitializers (InitializerElement[] els) throws SourceException {
342         getClassImpl ().changeInitializers (els, Impl.SET);
343     }
344
345     /** Get all the initializer blocks for this class.
346     * @return all the blocks
347     */

348     public InitializerElement[] getInitializers () {
349         return getClassImpl ().getInitializers ();
350     }
351
352     //================== Fields ===============================
353

354     /** Add a new field to the class.
355     * @param el the field to add
356     * @throws SourceException if impossible
357     */

358     public void addField (FieldElement el) throws SourceException {
359         if (getField(el.getName()) != null)
360             throwAddException("FMT_EXC_AddField", el); // NOI18N
361
getClassImpl ().changeFields (new FieldElement[] { el }, Impl.ADD);
362     }
363
364     /** Add some new fields to the class.
365     * @param els the fields to add
366     * @throws SourceException if impossible
367     */

368     public void addFields (final FieldElement[] els) throws SourceException {
369         for (int i = 0; i < els.length; i++)
370             if (getField(els[i].getName()) != null)
371                 throwAddException("FMT_EXC_AddField", els[i]); // NOI18N
372
getClassImpl ().changeFields (els, Impl.ADD);
373     }
374
375     /** Remove a field from the class.
376     * @param el the field to remove
377     * @throws SourceException if impossible
378     */

379     public void removeField (FieldElement el) throws SourceException {
380         getClassImpl ().changeFields (
381             new FieldElement[] { el }, Impl.REMOVE
382         );
383     }
384
385     /** Remove some fields from the class.
386     * @param els the fields to remove
387     * @throws SourceException if impossible
388     */

389     public void removeFields (final FieldElement[] els) throws SourceException {
390         getClassImpl ().changeFields (els, Impl.REMOVE);
391     }
392
393     /** Set the fields for this class.
394     * Previous fields are removed.
395     * @param els the new fields
396     * @throws SourceException if impossible
397     */

398     public void setFields (FieldElement[] els) throws SourceException {
399         getClassImpl ().changeFields (els, Impl.SET);
400     }
401
402     /** Get all fields in this class.
403     * @return the fields
404     */

405     public FieldElement[] getFields () {
406         return getClassImpl ().getFields ();
407     }
408
409     /** Find a field by name.
410     * @param name the name of the field to look for
411     * @return the element or <code>null</code> if not found
412     */

413     public FieldElement getField (Identifier name) {
414         return getClassImpl ().getField (name);
415     }
416
417
418     //================== Methods =================================
419

420     /** Add a method to this class. Note that the `el' object still
421     * refers to the original method while the ClassElement creates its
422     * own version/copy of it. Subsequent changes made to `el' will <B>not</B>
423     * affect the method newly created in this ClassElement, rather the
424     * original will be modified.
425     * @param el the method to add
426     * @throws SourceException if impossible
427     */

428     public void addMethod (MethodElement el) throws SourceException {
429         testMethod(el);
430         getClassImpl ().changeMethods (new MethodElement[] { el }, Impl.ADD);
431     }
432
433     /** Add some methods to this class. Note that the `els' objects still
434     * refer to original methods while the ClassElement creates its
435     * own versions/copies of them. Subsequent changes made to the passed objects will <B>not</B>
436     * affect the methods newly created in this ClassElement, rather the
437     * originals will be modified.
438     * @param els the methods to add
439     * @throws SourceException if impossible
440     */

441     public void addMethods (final MethodElement[] els) throws SourceException {
442         for (int i = 0; i < els.length; i++)
443             testMethod(els[i]);
444         getClassImpl ().changeMethods (els, Impl.ADD);
445     }
446
447     /** Test if the specified method already exists in the class.
448     * @param el The tested method
449     * @exception SourceException if method already exists in the class
450     */

451     private void testMethod(MethodElement el) throws SourceException {
452         MethodParameter[] params = el.getParameters();
453         Type[] types = new Type[params.length];
454         for (int i = 0; i < types.length; i++)
455             types[i] = params[i].getType();
456         if (getMethod(el.getName(), types) != null)
457             throwAddException("FMT_EXC_AddMethod", el); // NOI18N
458
}
459
460     /** Remove a method from this class.
461     * @param el the method to remove
462     * @throws SourceException if impossible
463     */

464     public void removeMethod (MethodElement el) throws SourceException {
465         getClassImpl ().changeMethods (
466             new MethodElement[] { el }, Impl.REMOVE
467         );
468     }
469
470     /** Remove some methods from this class.
471     * @param els the methods to remove
472     * @throws SourceException if impossible
473     */

474     public void removeMethods (final MethodElement[] els) throws SourceException {
475         getClassImpl ().changeMethods (els, Impl.REMOVE);
476     }
477
478     /** Set the methods for this class.
479     * The old ones are removed.
480     * @param els the new methods
481     * @throws SourceException if impossible
482     */

483     public void setMethods (MethodElement[] els) throws SourceException {
484         getClassImpl ().changeMethods (els, Impl.SET);
485     }
486
487     /** Get all methods in this class.
488     * @return the methods
489     */

490     public MethodElement[] getMethods () {
491         return getClassImpl ().getMethods ();
492     }
493
494     /** Find a method by signature.
495     * @param name the method name to look for
496     * @param arguments the argument types to look for
497     * @return the method, or <code>null</code> if it was not found
498     */

499     public MethodElement getMethod (Identifier name, Type[] arguments) {
500         return getClassImpl ().getMethod (name, arguments);
501     }
502
503
504     //================== Constructors ============================
505

506     /** Add a constructor to this class.
507     * @param el the constructor to add
508     * @throws SourceException if impossible
509     */

510     public void addConstructor (ConstructorElement el) throws SourceException {
511         testConstructor(el);
512         getClassImpl ().changeConstructors (new ConstructorElement[] { el }, Impl.ADD);
513     }
514
515     /** Add some constructors to this class.
516     * @param els the constructors to add
517     * @throws SourceException if impossible
518     */

519     public void addConstructors (final ConstructorElement[] els) throws SourceException {
520         for (int i = 0; i < els.length; i++)
521             testConstructor(els[i]);
522         getClassImpl ().changeConstructors (els, Impl.ADD);
523     }
524
525     /** Test if the specified constructor already exists in the class.
526     * @param el The tested constuctor
527     * @exception SourceException if constructor already exists in the class
528     */

529     private void testConstructor(ConstructorElement el) throws SourceException {
530         MethodParameter[] params = el.getParameters();
531         Type[] types = new Type[params.length];
532         for (int i = 0; i < types.length; i++)
533             types[i] = params[i].getType();
534         if (getConstructor(types) != null)
535             throwAddException("FMT_EXC_AddConstructor", el); // NOI18N
536
}
537
538     /** Remove a constructor from this class.
539     * @param el the constructor to remove
540     * @throws SourceException if impossible
541     */

542     public void removeConstructor (ConstructorElement el) throws SourceException {
543         getClassImpl ().changeConstructors (
544             new ConstructorElement[] { el }, Impl.REMOVE
545         );
546     }
547
548     /** Remove some constructors from this class.
549     * @param els the constructors to remove
550     * @throws SourceException if impossible
551     */

552     public void removeConstructors (final ConstructorElement[] els) throws SourceException {
553         getClassImpl ().changeConstructors (els, Impl.REMOVE);
554     }
555
556     /** Set the constructors for this class.
557     * The old ones are replaced.
558     * @param els the new constructors
559     * @throws SourceException if impossible
560     */

561     public void setConstructors (ConstructorElement[] els) throws SourceException {
562         getClassImpl ().changeConstructors (els, Impl.SET);
563     }
564
565     /** Get all constructors in this class.
566     * @return the constructors
567     */

568     public ConstructorElement[] getConstructors () {
569         return getClassImpl ().getConstructors ();
570     }
571
572     /** Find a constructor by signature.
573     * @param arguments the argument types to look for
574     * @return the constructor, or <code>null</code> if it does not exist
575     */

576     public ConstructorElement getConstructor (Type[] arguments) {
577         return getClassImpl ().getConstructor (arguments);
578     }
579
580
581     //================== Inner classes ==========================
582

583     /** Add a new inner class to this class.
584     * @param el the inner class to add
585     * @throws SourceException if impossible
586     */

587     public void addClass (ClassElement el) throws SourceException {
588         Identifier id = Identifier.create(el.getName().getName());
589         if (getClass(id) != null)
590             throwAddException("FMT_EXC_AddClass", el); // NOI18N
591
getClassImpl().changeClasses(new ClassElement[] { el }, Impl.ADD);
592     }
593
594     /** Add some new inner classes to this class.
595     * @param els the inner classes to add
596     * @throws SourceException if impossible
597     */

598     public void addClasses (final ClassElement[] els) throws SourceException {
599         Identifier id;
600
601         for (int i = 0; i < els.length; i++) {
602             id = Identifier.create(els[i].getName().getName());
603             if (getClass(id) != null)
604                 throwAddException("FMT_EXC_AddClass", els[i]); // NOI18N
605
}
606         getClassImpl ().changeClasses (els, Impl.ADD);
607     }
608
609     /** Remove an inner class from this class.
610     * @param el the inner class to remove
611     * @throws SourceException if impossible
612     */

613     public void removeClass (ClassElement el) throws SourceException {
614         getClassImpl ().changeClasses (new ClassElement[] { el }, Impl.REMOVE);
615     }
616
617     /** Remove some inner classes from this class.
618     * @param els the inner classes to remove
619     * @throws SourceException if impossible
620     */

621     public void removeClasses (final ClassElement[] els) throws SourceException {
622         getClassImpl ().changeClasses (els, Impl.REMOVE);
623     }
624
625     /** Set the inner classes for this class.
626     * The old ones are replaced.
627     * @param els the new inner classes
628     * @throws SourceException if impossible
629     */

630     public void setClasses (ClassElement[] els) throws SourceException {
631         getClassImpl ().changeClasses (els, Impl.SET);
632     }
633
634     /** Get all inner classes for this class.
635     * @return the inner classes
636     */

637     public ClassElement[] getClasses () {
638         return getClassImpl ().getClasses ();
639     }
640
641     /** Find an inner class by name.
642     * @param name the name to look for
643     * @return the inner class, or <code>null</code> if it does not exist
644     */

645     public ClassElement getClass (Identifier name) {
646         return getClassImpl ().getClass (name);
647     }
648
649
650     //================== Implements =============================
651

652     /** Add an interface to this class.
653     * I.e., one which this class will implement.
654     * @param in the interface to add, by name
655     * @throws SourceException if impossible
656     */

657     public void addInterface(Identifier in) throws SourceException {
658         getClassImpl ().changeInterfaces (new Identifier [] { in }, Impl.ADD);
659     }
660
661     /** Add some interfaces to this class.
662     * @param ins the interfaces to add, by name
663     * @throws SourceException if impossible
664     */

665     public void addInterfaces(final Identifier[] ins) throws SourceException {
666         getClassImpl ().changeInterfaces (ins, Impl.ADD);
667     }
668
669     /** Remove an interface from this class.
670     * @param in the interface to remove. by name
671     * @throws SourceException if impossible
672     */

673     public void removeInterface(Identifier in) throws SourceException {
674         getClassImpl ().changeInterfaces (new Identifier [] { in }, Impl.REMOVE);
675     }
676
677     /** Remove an interface from this class.
678     * @param in the interface to remove. by name
679     * @throws SourceException if impossible
680     * @deprecated the method's name is incorrect; please use removeInterface(i) instead.
681     */

682     public void removeInterfaces(Identifier in) throws SourceException {
683     removeInterface(in);
684     }
685
686     /** Remove some interfaces from this class.
687     * @param ins the interfaces to remove, by name
688     * @throws SourceException if impossible
689     */

690     public void removeInterfaces(final Identifier[] ins) throws SourceException {
691         getClassImpl ().changeInterfaces (ins, Impl.REMOVE);
692     }
693
694     /** Remove some interfaces from this class.
695     * @param ins the interfaces to remove, by name
696     * @throws SourceException if impossible
697     * @deprecated the method's name is incorrect; please use removeInterfaces(ins) instead.
698     */

699     public void removeInterface(final Identifier[] ins) throws SourceException {
700     removeInterfaces(ins);
701     }
702
703     /** Set the interfaces for this class.
704     * The old ones are replaced.
705     * @param ids the new interfaces, by name
706     * @throws SourceException if impossible
707     */

708     public void setInterfaces(Identifier[] ids) throws SourceException {
709         getClassImpl ().changeInterfaces (ids, Impl.SET);
710     }
711
712     /** Get all interfaces for this class.
713     * I.e., all interfaces which this class implements (directly),
714     * or (if an interface) all interfaces which it extends (directly).
715     * @return the interfaces
716     */

717     public Identifier[] getInterfaces () {
718         return getClassImpl ().getInterfaces ();
719     }
720
721     // ================ javadoc =========================================
722

723     /** Get the class documentation.
724     * @return the JavaDoc
725     */

726     public JavaDoc.Class getJavaDoc() {
727         return getClassImpl ().getJavaDoc ();
728     }
729
730     // ================ printing =========================================
731

732     /* Print this element to an element printer.
733     * @param printer the printer to print to
734     * @exception ElementPrinterInterruptException if the printer cancels the printing
735     */

736     public void print(ElementPrinter printer) throws ElementPrinterInterruptException {
737         printer.markClass(this, printer.ELEMENT_BEGIN);
738
739         JavaDoc doc = getJavaDoc();
740         if ((doc != null) && !doc.isEmpty()) {
741             printer.markClass(this, printer.JAVADOC_BEGIN); // JAVADOC begin
742
printJavaDoc(doc, printer);
743             printer.markClass(this, printer.JAVADOC_END); // JAVADOC end
744
printer.println(""); // NOI18N
745
}
746
747         printer.markClass(this, printer.HEADER_BEGIN); // HEADER begin
748
printer.print(isClass() ?
749                       HEADER_FORMAT[0].format(this) :
750                       HEADER_FORMAT[1].format(this)
751                      );
752         printer.markClass(this, printer.HEADER_END); // HEADER end
753

754         printer.print(" {"); // NOI18N
755
printer.markClass(this, printer.BODY_BEGIN); // BODY begin
756
printer.println(""); // NOI18N
757

758         if (print(getInitializers(), printer)) {
759             printer.println(""); // NOI18N
760
printer.println(""); // NOI18N
761
}
762
763         if (print(getFields(), printer)) {
764             printer.println(""); // NOI18N
765
printer.println(""); // NOI18N
766
}
767
768         if (print(getConstructors(), printer)) {
769             printer.println(""); // NOI18N
770
printer.println(""); // NOI18N
771
}
772
773         if (print(getMethods(), printer)) {
774             printer.println(""); // NOI18N
775
printer.println(""); // NOI18N
776
}
777
778         print(getClasses(), printer);
779
780         printer.println(""); // NOI18N
781
printer.markClass(this, printer.BODY_END); // BODY end
782
printer.print("}"); // NOI18N
783

784         printer.markClass(this, printer.ELEMENT_END);
785     }
786
787     // ================ misc =========================================
788

789     /** This method just throws localized exception. It is used during
790     * adding some element, which already exists in class.
791     * @param formatKey The message format key to localized bundle.
792     * @param element The element which can't be added
793     * @exception SourceException is alway thrown from this method.
794     */

795     private void throwAddException(String JavaDoc formatKey, MemberElement element) throws SourceException {
796     String JavaDoc msg = NbBundle.getMessage (ElementFormat.class, formatKey,
797         getName().getName(), element.getName().getName());
798     throwSourceException(msg);
799     }
800
801     /** Test whether this class has a declared main method
802     * and so may be executed directly.
803     * @return <CODE>true</CODE> if this class contains a
804     * <CODE>public static void main(String[])</CODE>
805     * method, otherwise <CODE>false</CODE>
806     */

807     public boolean hasMainMethod() {
808         MethodElement[] methods = getMethods();
809         Identifier mainId = Identifier.create("main"); // NOI18N
810

811         for (int i = 0; i < methods.length; i++) {
812             MethodElement m = methods[i];
813             if (m.getName().equals(mainId)) {
814                 if (m.getReturn() == Type.VOID) {
815                     if ((m.getModifiers() & ~Modifier.FINAL) == Modifier.PUBLIC + Modifier.STATIC) {
816                         MethodParameter[] params = m.getParameters();
817                         if (params.length == 1) {
818                             Type typ = params[0].getType();
819                             if (typ.isArray()) {
820                                 typ = typ.getElementType();
821                                 if (typ.isClass()) {
822                                     String JavaDoc name = typ.getClassName().getFullName();
823                                     if (name.equals("java.lang.String") || name.equals("String")) { // NOI18N
824
return true;
825                                     }
826                                 }
827                             }
828                         }
829                     }
830                 }
831             }
832         }
833         return false;
834     }
835
836     // [PENDING] mustn't it also implement Serializable? --jglick
837
/** Test whether this class is a JavaBean.
838     * It must:
839     * <UL>
840     * <LI> be declared as public
841     * <LI> not be declared as abstract or an interface
842     * <LI> have a default public constructor
843     * </UL>
844     * Note that these are technical requirements: satisfying them
845     * does not imply that the class is really <em>intended</em>
846     * to be used as a JavaBean; this could have been accidental.
847     * @return <CODE>true</CODE> if this class could be a JavaBean,
848     * otherwise <CODE>false</CODE>
849     */

850     public boolean isDeclaredAsJavaBean() {
851         if (Modifier.isPublic(getModifiers()) && !Modifier.isAbstract(getModifiers())) {
852             if (isClass()) {
853                 ConstructorElement[] constructors = getConstructors();
854                 for (int i = 0; i < constructors.length; i++) {
855                     if (constructors[i].getParameters().length == 0)
856                         if (Modifier.isPublic(constructors[i].getModifiers())) {
857                             return true;
858                         }
859                 }
860                 return (constructors.length == 0);
861             }
862         }
863         return false;
864     }
865
866     // [PENDING] concrete? public? what about extending [J]Applet indirectly? --jglick
867
/** Test whether this class is an applet.
868     * It must:
869     * <UL>
870     * <LI> be a class (not an interface)
871     * <LI> extend either <code>Applet</code> or <code>JApplet</code>
872     * </UL>
873     * @return <CODE>true</CODE> if this class could be an applet,
874     * otherwise <CODE>false</CODE>.
875     */

876     public boolean isDeclaredAsApplet() {
877         if (isClass()) {
878             Identifier superclass = getSuperclass();
879             if (superclass != null) {
880                 String JavaDoc name = superclass.getFullName();
881                 return name.equals("java.applet.Applet") || name.equals("javax.swing.JApplet"); // NOI18N
882
}
883         }
884         return false;
885     }
886
887     // ================ finders =======================================
888

889     /** List of finders */
890     private static List finders = new LinkedList();
891
892     /** Register a new finder for locating class elements.
893     * @param f the finder to add
894     */

895     public static void register (Finder f) {
896         synchronized (finders) {
897             finders.add (f);
898         }
899     }
900
901     /** Unregister a finder for locating class elements.
902     * @param f the finder to remove
903     */

904     public static void unregister (Finder f) {
905         synchronized (finders) {
906             finders.remove (f);
907         }
908     }
909
910     /**
911      * Search for a class element throughout the system.
912      * Asks all registered finders if they know where to find such a class.
913      * @param name class name separated by dots, e.g. <code>java.lang.String</code>.
914      * For inner classes is accepted delimiting by '$' or by '.'
915      * e.g. inner class A.B in package org.netbeans.test could
916      * be specified like: org.netbeans.A.B or org.netbeans.A$B
917      * Both possibilities are accepted.
918      * @param reference a file that is thought to belong to the same class path structure
919      * as the desired class, used as a reference point
920      * @return class element for that name, or <code>null</code> if none exists
921      * @see ClassElement.Finder
922      */

923     public static ClassElement forName(String JavaDoc name, FileObject reference) {
924         // 0. basic step is to try one of the registered finders
925
// and give them chance to search for a name of the element
926
Iterator it;
927
928         synchronized (finders) {
929             it = new ArrayList(finders).iterator();
930         }
931         while (it.hasNext ()) {
932             ClassElement el = ((Finder)it.next()).find(name, reference);
933             if (el != null)
934                 return el;
935         }
936         return null;
937     }
938
939     /** Search for a class element throughout the system.
940     * First goes through repository and find the appropriate DataObject
941     * Tests if it has SourceCookie and if there exist the right one,
942     * it is returned. Otherwise tries to creates the Class.forName
943     * and asks all registered finders if they know where to find such a class.
944     *
945     * @param name class name separated by dots, e.g. <code>java.lang.String</code>.
946     * For inner classes is accepted delimiting by '$' or by '.'
947     * e.g. inner class A.B in package org.netbeans.test could
948     * be specified like: org.netbeans.A.B or org.netbeans.A$B
949     * Both possibilities are accepted.
950     * @return class element for that name, or <code>null</code> if none exists
951     * @see ClassElement.Finder
952     * @deprecated This method variant can no longer work. Use {@link #forName(String,FileObject)} instead.
953     */

954     public static ClassElement forName(String JavaDoc name) {
955         throw new UnsupportedOperationException JavaDoc("The operation is no longer supported, use ClassElement.forName(String,FileObject)"); // NOI18N
956
}
957
958
959     /**
960      * Search for a class element throughout the system.
961      * Asks all registered finders if they know where to find such a class.
962      * @param clazz class name separated by dots, e.g. <code>java.lang.String</code>
963      * @param reference a file that is thought to belong to the same class path structure
964      * as the desired class, used as a reference point
965      * @return class element for that name, or <code>null</code> if none exists
966      * @see ClassElement.Finder
967      */

968     public static ClassElement forClass(Class JavaDoc clazz, FileObject reference) {
969         Iterator it;
970
971         synchronized (finders) {
972             it = new ArrayList(finders).iterator();
973         }
974         while (it.hasNext ()) {
975             ClassElement el = ((Finder)it.next()).find(clazz, reference);
976             if (el != null)
977                 return el;
978         }
979         return null;
980     }
981
982     /** Search for a class element throughout the system.
983     * Asks all registered finders if they know where to find such a class.
984     * @param clazz class name separated by dots, e.g. <code>java.lang.String</code>
985     * @return class element for that name, or <code>null</code> if none exists
986     * @see ClassElement.Finder
987     * @deprecated This method variant can no longer work. Use {@link #forClass(Class,FileObject)} instead.
988     */

989     public static ClassElement forClass(Class JavaDoc clazz) {
990         return forClass (clazz, null);
991     }
992
993
994     /** Provides a "finder" for class elements.
995     * A module can provide its own finder to enhance the ability
996     * of the IDE to locate a valid class element description for different classes.
997     * @see ClassElement#forName
998     * @see ClassElement#register
999     * @see ClassElement#unregister
1000    */

1001    public static interface Finder {
1002        /** Find a class element description for a class.
1003        *
1004        * @param clazz the class to find
1005        * @param reference file object presumed to be in the same classpath structure
1006        * @return the class element, or <code>null</code> if not found
1007        */

1008        public ClassElement find(Class JavaDoc clazz, FileObject reference);
1009
1010        /** Find a class element description for a class name.
1011        *
1012        * @param name the name of a class to find
1013        * @param reference file object presumed to be in the same classpath structure
1014        * @return the class element, or <code>null</code> if not found
1015        */

1016        public ClassElement find(String JavaDoc name, FileObject reference);
1017    }
1018
1019    // ================ implementation ===================================
1020

1021    /** Pluggable behavior for class elements.
1022    * @see ClassElement
1023    */

1024    public static interface Impl extends MemberElement.Impl {
1025        /** Add some items. */
1026        public static final int ADD = 1;
1027        /** Remove some items. */
1028        public static final int REMOVE = -1;
1029        /** Set some items, replacing the old ones. */
1030        public static final int SET = 0;
1031
1032        /** @deprecated Only public by accident. */
1033        /* public static final */ long serialVersionUID = 2564194659099459416L;
1034
1035        /** Set the superclass for this class.
1036        * @param superClass the superclass, by name
1037        * @throws SourceException if impossible
1038        */

1039        public void setSuperclass(Identifier superClass) throws SourceException;
1040
1041        /** Get the superclass for this class.
1042        * @return the superclass, by name
1043        */

1044        public Identifier getSuperclass();
1045
1046        /** Set whether this is a class or interface.
1047        * @param isClass either {@link ClassElement#CLASS} or {@link ClassElement#INTERFACE}
1048        * @throws SourceException if impossible
1049        */

1050        public void setClassOrInterface(boolean isClass) throws SourceException;
1051
1052        /** Test whether this is a class or interface.
1053        * @return either {@link ClassElement#CLASS} or {@link ClassElement#INTERFACE}
1054        */

1055        public boolean isClassOrInterface();
1056
1057        /** Change the set of initializers.
1058        * @param elems the new initializers
1059        * @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
1060        * @exception SourceException if impossible
1061        */

1062        public void changeInitializers (InitializerElement[] elems, int action) throws SourceException;
1063
1064        /** Get all initializers.
1065        * @return the initializers
1066        */

1067        public InitializerElement[] getInitializers ();
1068
1069        /** Change the set of fields.
1070        * @param elems the new fields
1071        * @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
1072        * @exception SourceException if impossible
1073        */

1074        public void changeFields (FieldElement[] elems, int action) throws SourceException;
1075
1076        /** Get all fields.
1077        * @return the fields
1078        */

1079        public FieldElement[] getFields ();
1080
1081        /** Find a field by name.
1082        * @param name the name to look for
1083        * @return the field, or <code>null</code> if it does not exist
1084        */

1085        public FieldElement getField (Identifier name);
1086
1087        /** Change the set of methods.
1088        * @param elems the new methods
1089        * @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
1090        * @exception SourceException if impossible
1091        */

1092        public void changeMethods (MethodElement[] elems, int action) throws SourceException;
1093
1094        /** Get all methods.
1095        * @return the methods
1096        */

1097        public MethodElement[] getMethods ();
1098
1099        /** Finds a method by signature.
1100        * @param name the name to look for
1101        * @param arguments the argument types to look for
1102        * @return the method, or <code>null</code> if it does not exist
1103        */

1104        public MethodElement getMethod (Identifier name, Type[] arguments);
1105
1106        /** Change the set of constructors.
1107        * @param elems the new constructors
1108        * @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
1109        * @exception SourceException if impossible
1110        */

1111        public void changeConstructors (ConstructorElement[] elems, int action) throws SourceException;
1112
1113        /** Get all constructors.
1114        * @return the constructors
1115        */

1116        public ConstructorElement[] getConstructors ();
1117
1118        /** Find a constructor by signature.
1119        * @param arguments the argument types to look for
1120        * @return the constructor, or <code>null</code> if it does not exist
1121        */

1122        public ConstructorElement getConstructor (Type[] arguments);
1123
1124
1125        /** Change the set of inner classes.
1126        * @param elems the new inner classes
1127        * @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
1128        * @exception SourceException if impossible
1129        */

1130        public void changeClasses (ClassElement[] elems, int action) throws SourceException;
1131
1132        /** Get all inner classes.
1133        * @return the inner classes
1134        */

1135        public ClassElement[] getClasses ();
1136
1137        /** Find an inner class by name.
1138        * @param name the name to look for
1139        * @return the inner class, or <code>null</code> if it does not exist
1140        */

1141        public ClassElement getClass (Identifier name);
1142
1143        /** Change the set of implemented/extended interfaces.
1144        * @param ids the new interfaces, by name
1145        * @param action {@link #ADD}, {@link #REMOVE}, or {@link #SET}
1146        * @exception SourceException if impossible
1147        */

1148        public void changeInterfaces (Identifier[] ids, int action) throws SourceException;
1149
1150        /** Get all implemented/extended interfaces.
1151        * @return the interfaces, by name
1152        */

1153        public Identifier[] getInterfaces ();
1154
1155        /** Get the class's documentation block.
1156        * @return JavaDoc for the class (not its members)
1157        */

1158        public JavaDoc.Class getJavaDoc();
1159    }
1160
1161    /** Memory based implementation of the element factory.
1162    */

1163  static final class Memory extends MemberElement.Memory implements Impl {
1164        /** property, need not be initialized */
1165        private Identifier superClass;
1166        /** is class or interface */
1167        private boolean isClass;
1168
1169        /** collection of interfaces */
1170        private MemoryCollection interfaces;
1171
1172        /** collection of initializers */
1173        private MemoryCollection.Initializer initializers;
1174
1175        /** collection of constructors */
1176        private MemoryCollection.Constructor constructors;
1177        /** collection of methods */
1178        private MemoryCollection.Method methods;
1179        /** collection of fields */
1180        private MemoryCollection.Field fields;
1181        /** collection of classes */
1182        private MemoryCollection.Class classes;
1183
1184        /** memory implementation of java doc */
1185        JavaDoc.Class javaDoc = null;
1186
1187        static final long serialVersionUID =6058485742932189851L;
1188
1189        public Memory() {
1190            superClass = null;
1191            isClass = true;
1192            javaDoc = JavaDocSupport.createClassJavaDoc( null );
1193        }
1194
1195        /** Copy constructor.
1196        * @param el element to copy from
1197        */

1198        public Memory(ClassElement el) {
1199            super (el);
1200            superClass = el.getSuperclass ();
1201            isClass = el.isClassOrInterface ();
1202            javaDoc = el.getJavaDoc().isEmpty() ?
1203                      JavaDocSupport.createClassJavaDoc( null ) :
1204                      JavaDocSupport.createClassJavaDoc( el.getJavaDoc().getRawText() );
1205        }
1206
1207        void updateNameToParent() {
1208            // set the proper name first, according to the outer element's name:
1209
MemberElement me = (MemberElement)this.element;
1210            if (me.getDeclaringClass() == null)
1211                // we have just the name the caller has given to us.
1212
return;
1213            StringBuffer JavaDoc fullName = new StringBuffer JavaDoc();
1214            String JavaDoc simpleName;
1215
1216            fullName.append(me.getDeclaringClass().getName().getFullName());
1217            fullName.append('.');
1218            fullName.append(simpleName = getName().getName());
1219            this.setName(Identifier.create(fullName.toString(), simpleName));
1220        }
1221
1222        void initialize(ClassElement model) {
1223            updateNameToParent();
1224            copyFrom(model);
1225        }
1226
1227        /** Late initialization of initialization of copy elements.
1228        */

1229        public void copyFrom (ClassElement copyFrom) {
1230            changeInterfaces (copyFrom.getInterfaces (), SET);
1231            changeConstructors (copyFrom.getConstructors (), SET);
1232            changeMethods (copyFrom.getMethods (), SET);
1233            changeFields (copyFrom.getFields (), SET);
1234            changeClasses (copyFrom.getClasses (), SET);
1235        }
1236
1237        /** Setter
1238        */

1239        public void setSuperclass(Identifier superClass) throws SourceException {
1240            Identifier old = this.superClass;
1241            this.superClass = superClass;
1242            firePropertyChange (PROP_SUPERCLASS, old, superClass);
1243        }
1244
1245        public Identifier getSuperclass() {
1246            return superClass;
1247        }
1248
1249        public void setClassOrInterface(boolean isClass) {
1250            boolean old = this.isClass;
1251            this.isClass = isClass;
1252            firePropertyChange (PROP_CLASS_OR_INTERFACE,
1253                                old ? Boolean.TRUE : Boolean.FALSE,
1254                                isClass ? Boolean.TRUE : Boolean.FALSE);
1255        }
1256
1257        public boolean isClassOrInterface() {
1258            return isClass;
1259        }
1260
1261        /** Changes set of elements.
1262        * @param elems elements to change
1263        * @param action the action to do (ADD, REMOVE, SET)
1264        * @exception SourceException if the action cannot be handled
1265        */

1266        public synchronized void changeInitializers (InitializerElement[] elems, int action) {
1267            initInitializers();
1268            initializers.change (elems, action);
1269        }
1270
1271        public synchronized InitializerElement[] getInitializers () {
1272            initInitializers();
1273            return (InitializerElement[])initializers.toArray ();
1274        }
1275
1276        void initInitializers() {
1277            if (initializers == null) {
1278                initializers = new MemoryCollection.Initializer (this);
1279            }
1280        }
1281
1282        /** Changes set of elements.
1283        * @param elems elements to change
1284        * @exception SourceException if the action cannot be handled
1285        */

1286        public synchronized void changeFields (FieldElement[] elems, int action) {
1287            initFields();
1288            fields.change (elems, action);
1289        }
1290
1291        public synchronized FieldElement[] getFields () {
1292            initFields();
1293            return (FieldElement[])fields.toArray ();
1294        }
1295
1296        /** Finds a field with given name.
1297        * @param name the name of field to look for
1298        * @return the element or null if field with such name does not exist
1299        */

1300        public synchronized FieldElement getField (Identifier name) {
1301            initFields();
1302            return (FieldElement)fields.find (name, null);
1303        }
1304
1305        void initFields() {
1306            if (fields == null) {
1307                fields = new MemoryCollection.Field (this);
1308            }
1309        }
1310
1311        /** Changes set of elements.
1312        * @param elems elements to change
1313        */

1314        public synchronized void changeMethods (MethodElement[] elems, int action) {
1315            initMethods();
1316            methods.change (elems, action);
1317        }
1318
1319        public MethodElement[] getMethods () {
1320            initMethods();
1321            return (MethodElement[])methods.toArray ();
1322        }
1323
1324        /** Finds a method with given name and argument types.
1325        * @param name the name of field to look for
1326        * @param arguments for the method
1327        * @return the element or null if such method does not exist
1328        */

1329        public synchronized MethodElement getMethod (Identifier name, Type[] arguments) {
1330            initMethods();
1331            return (MethodElement)methods.find (name, arguments);
1332        }
1333
1334        void initMethods() {
1335            if (methods == null) {
1336                methods = new MemoryCollection.Method (this);
1337            }
1338        }
1339
1340        /** Changes set of elements.
1341        * @param elems elements to change
1342        * @exception SourceException if the action cannot be handled
1343        */

1344        public synchronized void changeConstructors (ConstructorElement[] elems, int action) {
1345            initConstructors();
1346            constructors.change (elems, action);
1347        }
1348
1349        public synchronized ConstructorElement[] getConstructors () {
1350            initConstructors();
1351            return (ConstructorElement[])constructors.toArray ();
1352        }
1353
1354        /** Finds a constructor with argument types.
1355        * @param arguments for the method
1356        * @return the element or null if such method does not exist
1357        */

1358        public synchronized ConstructorElement getConstructor (Type[] arguments) {
1359            initConstructors();
1360            return (ConstructorElement)constructors.find (null, arguments);
1361        }
1362
1363        void initConstructors() {
1364            if (constructors == null) {
1365                constructors = new MemoryCollection.Constructor (this);
1366            }
1367        }
1368
1369        /** Changes set of elements.
1370        * @param elems elements to change
1371        */

1372        public synchronized void changeClasses (ClassElement[] elems, int action) {
1373            initClasses();
1374            classes.change (elems, action);
1375        }
1376
1377        public synchronized ClassElement[] getClasses () {
1378            initClasses();
1379            return (ClassElement[])classes.toArray ();
1380        }
1381
1382        /** Finds an inner class with given name.
1383        * @param name the name to look for
1384        * @return the element or null if such class does not exist
1385        */

1386        public synchronized ClassElement getClass (Identifier name) {
1387            initClasses();
1388            return (ClassElement)classes.find (name, null);
1389        }
1390
1391        void initClasses() {
1392            if (classes == null) {
1393                classes = new MemoryCollection.Class (this);
1394            }
1395        }
1396
1397        /** Changes interfaces this class implements (or extends).
1398        * @param ids identifiers to change
1399        */

1400        public synchronized void changeInterfaces (Identifier[] ids, int action) {
1401            initInterfaces();
1402            interfaces.change (ids, action);
1403        }
1404
1405        /** @return all interfaces which this class implements or interface extends.
1406        */

1407        public synchronized Identifier[] getInterfaces () {
1408            initInterfaces();
1409            return (Identifier[])interfaces.toArray ();
1410        }
1411
1412        void initInterfaces() {
1413            if (interfaces == null) {
1414                interfaces = new MemoryCollection.Interface(this);
1415            }
1416        }
1417
1418        void markCurrent(Element marker, boolean after) {
1419            MemoryCollection col;
1420
1421            if (marker instanceof InitializerElement) {
1422                col = initializers;
1423            } else if (marker instanceof ClassElement) {
1424                col = classes;
1425            } else if (marker instanceof FieldElement) {
1426                col = fields;
1427            } else if (marker instanceof MethodElement) {
1428                col = methods;
1429            } else if (marker instanceof ConstructorElement) {
1430                col = constructors;
1431            } else {
1432                throw new IllegalArgumentException JavaDoc();
1433            }
1434            col.markCurrent(marker, after);
1435        }
1436
1437        // ================ javadoc =========================================
1438

1439        /** @return class documentation.
1440        */

1441        public JavaDoc.Class getJavaDoc() {
1442            return javaDoc;
1443        }
1444
1445        /** Getter for the associated class
1446        * @return the class element for this impl
1447        */

1448        final ClassElement getClassElement () {
1449            return (ClassElement)element;
1450        }
1451
1452        // ================ serialization ======================================
1453

1454        public Object JavaDoc readResolve() {
1455            return new ClassElement(this, (SourceElement)null);
1456        }
1457
1458    }
1459}
1460
Popular Tags