View Javadoc

1   /**
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@codehaus.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.codehaus.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2001-2002 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  package org.codehaus.modello.plugin.java.javasource;
47  
48  /*
49   * Copyright (c) 2004, Codehaus.org
50   *
51   * Permission is hereby granted, free of charge, to any person obtaining a copy of
52   * this software and associated documentation files (the "Software"), to deal in
53   * the Software without restriction, including without limitation the rights to
54   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
55   * of the Software, and to permit persons to whom the Software is furnished to do
56   * so, subject to the following conditions:
57   *
58   * The above copyright notice and this permission notice shall be included in all
59   * copies or substantial portions of the Software.
60   *
61   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
64   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
66   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
67   * SOFTWARE.
68   */
69  
70  import java.util.ArrayList;
71  import java.util.Enumeration;
72  import java.util.List;
73  import java.util.Vector;
74  
75  /**
76   * A representation of the Java Source code for a Java Interface.
77   * This is a useful utility when creating in memory source code.
78   * The code in this package was modelled after the Java Reflection API
79   * as much as possible to reduce the learning curve.
80   *
81   * @author <a href="mailto:skopp@riege.de">Martin Skopp</a>
82   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
83   * @version $Revision$ $Date$
84   **/
85  public final class JInterface extends JStructure
86  {
87  
88  
89      /**
90       * The fields for this JInterface
91       */
92      private JNamedMap fields = null;
93  
94      /**
95       * The list of methods of this JInterface
96       */
97      private Vector<JMethodSignature> methods = null;
98  
99  
100     /**
101      * Creates a new JInterface with the given name.
102      *
103      * @param name the name of the JInterface.
104      * @throws java.lang.IllegalArgumentException when the given name
105      * is not a valid Class name.
106      **/
107     public JInterface( String name )
108         throws IllegalArgumentException
109     {
110         super( name );
111         methods = new Vector<JMethodSignature>();
112 
113         //-- initialize default Java doc
114         getJDocComment().appendComment( "Interface " + getLocalName() + "." );
115 
116     } //-- JInterface
117 
118     /**
119      * Adds the given JField to this JStructure.
120      * <p>
121      * This method is implemented by subclasses and
122      * should only accept the proper fields for the
123      * subclass otherwise an IllegalArgumentException
124      * will be thrown. For example a JInterface will
125      * only accept static fields.
126      * <p>
127      * @param jField, the JField to add
128      * @exception java.lang.IllegalArgumentException when the given
129      * JField has a name of an existing JField
130      */
131     public void addField( JField jField )
132         throws IllegalArgumentException
133     {
134         if ( jField == null )
135         {
136             throw new IllegalArgumentException( "argument 'jField' cannot be null" );
137         }
138 
139         String name = jField.getName();
140 
141         //-- check for duplicate field name
142         if ( ( fields != null ) && ( fields.get( name ) != null ) )
143         {
144             String err = "duplicate name found: " + name;
145             throw new IllegalArgumentException( err );
146         }
147 
148         //-- check for proper modifiers
149         JModifiers modifiers = jField.getModifiers();
150         if ( !modifiers.isStatic() )
151         {
152             throw new IllegalArgumentException( "Fields added to a JInterface must be static." );
153         }
154         if ( modifiers.isPrivate() )
155         {
156             throw new IllegalArgumentException( "Fields added to a JInterface must not be private." );
157         }
158 
159         //-- only initialize fields if we need it, many interfaces
160         //-- don't contain any fields, no need to waste space
161         if ( fields == null )
162         {
163             fields = new JNamedMap( 3 );
164         }
165 
166         fields.put( name, jField );
167     }
168 
169     /**
170      * Adds the given JMember to this JStructure.
171      * <p>
172      * This method is implemented by subclasses and
173      * should only accept the proper types for the
174      * subclass otherwise an IllegalArgumentException
175      * will be thrown.
176      * <p>
177      * @param jMember the JMember to add to this JStructure.
178      * @throws java.lang.IllegalArgumentException when the given
179      * JMember has the same name of an existing JField
180      * or JMethod respectively.
181      */
182     public void addMember( JMember jMember )
183         throws IllegalArgumentException
184     {
185         if ( jMember == null )
186         {
187             throw new IllegalArgumentException( "argument 'jMember' may not be null." );
188         }
189         if ( jMember instanceof JField )
190         {
191             addField( (JField) jMember );
192         }
193         else
194         {
195             throw new IllegalArgumentException( "invalid member for JInterface: " +
196                                                 jMember.toString() );
197         }
198 
199     } //-- addMember
200 
201 
202     /**
203      * Adds the given JMethodSignature to this JClass
204      *
205      * @param jMethodSig the JMethodSignature to add.
206      * @throws java.lang.IllegalArgumentException when the given
207      * JMethodSignature conflicts with an existing
208      * method signature.
209      */
210     public void addMethod( JMethodSignature jMethodSig )
211         throws IllegalArgumentException
212     {
213         if ( jMethodSig == null )
214         {
215             String err = "The JMethodSignature cannot be null.";
216             throw new IllegalArgumentException( err );
217         }
218 
219         //-- check method name and signatures *add later*
220 
221         //-- keep method list sorted for esthetics when printing
222         //-- START SORT :-)
223         boolean added = false;
224 //        short modifierVal = 0;
225         JModifiers modifiers = jMethodSig.getModifiers();
226         for ( int i = 0; i < methods.size(); i++ )
227         {
228             JMethodSignature tmp = (JMethodSignature) methods.elementAt( i );
229             //-- first compare modifiers
230             if ( tmp.getModifiers().isProtected() )
231             {
232                 if ( !modifiers.isProtected() )
233                 {
234                     methods.insertElementAt( jMethodSig, i );
235                     added = true;
236                     break;
237                 }
238             }
239             //-- compare names
240             if ( jMethodSig.getName().compareTo( tmp.getName() ) < 0 )
241             {
242                 methods.insertElementAt( jMethodSig, i );
243                 added = true;
244                 break;
245             }
246         }
247         //-- END SORT
248         if ( !added ) methods.addElement( jMethodSig );
249 
250         //-- check return type to make sure it's included in the
251         //-- import list
252         JType jType = jMethodSig.getReturnType();
253         if ( jType != null )
254         {
255             while ( jType.isArray() )
256                 jType = jType.getComponentType();
257 
258             if ( !jType.isPrimitive() )
259                 addImport( jType.getName() );
260         }
261         //-- check exceptions
262         JClass[] exceptions = jMethodSig.getExceptions();
263         for ( JClass exception : exceptions )
264         {
265             addImport( exception.getName() );
266         }
267     } //-- addMethod
268 
269     /**
270      * Returns the field with the given name, or null if no field
271      * was found with the given name.
272      *
273      * @param name the name of the field to return.
274      * @return the field with the given name, or null if no field
275      * was found with the given name.
276      */
277     public JField getField( String name )
278     {
279         if ( fields == null ) return null;
280         return (JField) fields.get( name );
281     } //-- getField
282 
283     /**
284      * Returns an array of all the JFields of this JStructure
285      *
286      * @return an array of all the JFields of this JStructure
287      */
288     public JField[] getFields()
289     {
290         if ( fields == null )
291         {
292             return new JField[0];
293         }
294         int size = fields.size();
295         JField[] farray = new JField[size];
296         for ( int i = 0; i < size; i++ )
297         {
298             farray[i] = (JField) fields.get( i );
299         }
300         return farray;
301     } //-- getFields
302 
303 
304     /**
305      * Returns an array of all the JMethodSignatures of this JInterface.
306      *
307      * @return an array of all the JMethodSignatures of this JInterface.
308      **/
309     public JMethodSignature[] getMethods()
310     {
311         JMethodSignature[] marray = new JMethodSignature[methods.size()];
312         methods.copyInto( marray );
313         return marray;
314     } //-- getMethods
315 
316     /**
317      * Returns the JMethodSignature with the given name,
318      * and occuring at or after the given starting index.
319      *
320      * @param name the name of the JMethodSignature to return.
321      * @param startIndex the starting index to begin searching
322      * from.
323      * @return the JMethodSignature, or null if not found.
324      **/
325     public JMethodSignature getMethod( String name, int startIndex )
326     {
327         for ( int i = startIndex; i < methods.size(); i++ )
328         {
329             JMethodSignature jMethod = (JMethodSignature) methods.elementAt( i );
330             if ( jMethod.getName().equals( name ) ) return jMethod;
331         }
332         return null;
333     } //-- getMethod
334 
335     /**
336      * Returns the JMethodSignature at the given index.
337      *
338      * @param index the index of the JMethodSignature to return.
339      * @return the JMethodSignature at the given index.
340      **/
341     public JMethodSignature getMethod( int index )
342     {
343         return (JMethodSignature) methods.elementAt( index );
344     } //-- getMethod
345 
346 
347     /**
348      * Prints the source code for this JInterface to the given JSourceWriter
349      *
350      * @param jsw the JSourceWriter to print to. [May not be null]
351      */
352     public void print( JSourceWriter jsw )
353     {
354         print( jsw, false );
355     }
356 
357     /**
358      * Prints the source code for this JInterface to the given JSourceWriter
359      *
360      * @param jsw the JSourceWriter to print to. [May not be null]
361      */
362     public void print( JSourceWriter jsw, boolean classOnly )
363     {
364 
365         if ( jsw == null )
366         {
367             throw new IllegalArgumentException( "argument 'jsw' should not be null." );
368         }
369 
370         StringBuilder buffer = new StringBuilder();
371 
372         if ( !classOnly )
373         {
374             printHeader( jsw );
375             printPackageDeclaration( jsw );
376             printImportDeclarations( jsw );
377         }
378 
379         //------------/
380         //- Java Doc -/
381         //------------/
382 
383         getJDocComment().print( jsw );
384 
385         JAnnotations annotations = getAnnotations();
386         if ( annotations != null ) annotations.print( jsw );
387 
388         //-- print class information
389         //-- we need to add some JavaDoc API adding comments
390 
391         buffer.setLength( 0 );
392 
393         JModifiers modifiers = getModifiers();
394         if ( modifiers.isPrivate() )
395         {
396             buffer.append( "private " );
397         }
398         else if ( modifiers.isPublic() )
399         {
400             buffer.append( "public " );
401         }
402 
403         if ( modifiers.isAbstract() )
404         {
405             buffer.append( "abstract " );
406         }
407 
408         buffer.append( "interface " );
409         buffer.append( getLocalName() );
410         jsw.writeln( buffer.toString() );
411         buffer.setLength( 0 );
412         jsw.indent();
413 
414         if ( getInterfaceCount() > 0 )
415         {
416             Enumeration<String> e = getInterfaces();
417             buffer.append( "extends " );
418             while ( e.hasMoreElements() )
419             {
420                 buffer.append( e.nextElement() );
421                 if ( e.hasMoreElements() ) buffer.append( ", " );
422             }
423 
424             jsw.writeln( buffer.toString() );
425             buffer.setLength( 0 );
426         }
427 
428         jsw.unindent();
429 
430         jsw.writeln( '{' );
431 
432         jsw.indent();
433 
434         //-- declare static members
435 
436         if ( fields != null )
437         {
438             if ( fields.size() > 0 )
439             {
440                 jsw.writeln();
441                 jsw.writeln( "  //--------------------------/" );
442                 jsw.writeln( " //- Class/Member Variables -/" );
443                 jsw.writeln( "//--------------------------/" );
444                 jsw.writeln();
445             }
446 
447 
448             for ( int i = 0; i < fields.size(); i++ )
449             {
450 
451                 JField jField = (JField) fields.get( i );
452 
453                 //-- print Java comment
454                 JDocComment comment = jField.getComment();
455                 if ( comment != null ) comment.print( jsw );
456 
457                 // -- print member
458                 jsw.write( jField.getModifiers().toString() );
459                 jsw.write( ' ' );
460 
461                 JType type = jField.getType();
462                 String typeName = type.toString();
463                 //-- for esthetics use short name in some cases
464                 if ( typeName.equals( toString() ) )
465                 {
466                     typeName = type.getLocalName();
467                 }
468                 jsw.write( typeName );
469                 jsw.write( ' ' );
470                 jsw.write( jField.getName() );
471 
472                 String init = jField.getInitString();
473                 if ( init != null )
474                 {
475                     jsw.write( " = " );
476                     jsw.write( init );
477                 }
478 
479                 jsw.writeln( ';' );
480                 jsw.writeln();
481             }
482         }
483 
484         //-- print method signatures
485 
486         if ( methods.size() > 0 )
487         {
488             jsw.writeln();
489             jsw.writeln( "  //-----------/" );
490             jsw.writeln( " //- Methods -/" );
491             jsw.writeln( "//-----------/" );
492             jsw.writeln();
493         }
494 
495         for ( int i = 0; i < methods.size(); i++ )
496         {
497             JMethodSignature signature = (JMethodSignature) methods.elementAt( i );
498             signature.print( jsw );
499             jsw.writeln( ';' );
500         }
501 
502         for ( String sourceCodeEntry : sourceCodeEntries )
503         {
504             jsw.writeln( sourceCodeEntry );
505         }
506 
507         jsw.unindent();
508         jsw.writeln( '}' );
509         jsw.flush();
510         jsw.close();
511     } //-- printSource
512 
513     private List<String> sourceCodeEntries = new ArrayList<String>();
514 
515     public void addSourceCode( String sourceCode )
516     {
517         sourceCodeEntries.add( sourceCode );
518     }
519 
520     /**
521      * Test drive method...to be removed or commented out
522      **
523      public static void main(String[] args) {
524      JInterface jInterface = new JInterface("Test");
525 
526      //-- add an import
527      jInterface.addImport("java.util.Vector");
528      JClass jString = new JClass("String");
529 
530      //-- add an interface
531      jInterface.addInterface("java.io.Serializable");
532 
533      //-- add a static field
534      JField jField = new JField(new JClass("java.lang.String"), "TEST");
535      jField.setInitString("\"Test\"");
536      jField.getModifiers().setStatic(true);
537      jField.getModifiers().makePublic();
538      jInterface.addField(jField);
539 
540      //-- add a method signature
541      JMethodSignature jMethodSig = new JMethodSignature("getName", jString);
542      jInterface.addMethod(jMethodSig);
543      jInterface.print();
544      } //-- main
545      /* */
546 
547 } //-- JInterface