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.io.File;
71  import java.util.Enumeration;
72  import java.util.Vector;
73  
74  import org.codehaus.plexus.util.WriterFactory;
75  
76  /**
77   * This class represents the basic Java "structure" for a Java
78   * source file. This is the base class for JClass and JInterface.
79   *
80   * This is a useful utility when creating in memory source code.
81   * The code in this package was modelled after the Java Reflection API
82   * as much as possible to reduce the learning curve.
83   *
84   * @author <a href="mailto:skopp@riege.de">Martin Skopp</a>
85   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
86   * @version $Revision$ $Date$
87   */
88  public abstract class JStructure extends JType
89  {
90  
91      /**
92       * The Id for Source control systems
93       * I needed to separate this line to prevent CVS from
94       * expanding it here! ;-)
95       */
96      static final String DEFAULT_HEADER
97          = "$" + "Id$";
98  
99      /**
100      * The source control version for listed in the JavaDoc
101      * I needed to separate this line to prevent CVS from
102      * expanding it here! ;-)
103      */
104     static final String version = "$" + "Revision$ $" + "Date$";
105 
106     /**
107      * The source header
108      */
109     private JComment header = null;
110 
111     /**
112      * List of imported classes and packages
113      */
114     private Vector<String> imports = null;
115 
116     /**
117      * The set of interfaces implemented/extended by this JStructure
118      */
119     private Vector<String> interfaces = null;
120 
121     /**
122      * The Javadoc for this JStructure
123      */
124     private JDocComment jdc = null;
125 
126     /**
127      * The JModifiers for this JStructure, which allows us to
128      * change the resulting qualifiers
129      */
130     private JModifiers modifiers = null;
131 
132     /**
133      * The package to which this JStructure belongs
134      */
135     private String packageName = null;
136 
137     private JAnnotations annotations = null;
138 
139     /**
140      * Creates a new JStructure with the given name.
141      *
142      * @param name the name of the JStructure.
143      * @throws java.lang.IllegalArgumentException when the given name
144      * is not a valid Class name.
145      */
146     protected JStructure( String name )
147         throws IllegalArgumentException
148     {
149         super( name );
150 
151         //-- verify name is a valid java class name
152         if ( !isValidClassName( name ) )
153         {
154             String lname = getLocalName();
155             String err = "'" + lname + "' is ";
156             if ( JNaming.isKeyword( lname ) )
157                 err += "a reserved word and may not be used as "
158                     + " a class name.";
159             else
160                 err += "not a valid Java identifier.";
161 
162             throw new IllegalArgumentException( err );
163         }
164         this.packageName = getPackageFromClassName( name );
165         imports = new Vector<String>();
166         interfaces = new Vector<String>();
167         jdc = new JDocComment();
168         modifiers = new JModifiers();
169         //-- initialize default Java doc
170         jdc.addDescriptor( JDocDescriptor.createVersionDesc( version ) );
171 
172     } //-- JStructure
173 
174     /**
175      * Adds the given JField to this JStructure.
176      * <p>
177      * This method is implemented by subclasses and
178      * should only accept the proper fields for the
179      * subclass otherwise an IllegalArgumentException
180      * will be thrown. For example a JInterface will
181      * only accept static fields.
182      * <p>
183      * @param jField, the JField to add
184      * @exception java.lang.IllegalArgumentException when the given
185      * JField has a name of an existing JField
186      */
187     public abstract void addField( JField jField )
188         throws IllegalArgumentException;
189 
190     /**
191      * Adds the given JMember to this JStructure.
192      * <p>
193      * This method is implemented by subclasses and
194      * should only accept the proper types for the
195      * subclass otherwise an IllegalArgumentException
196      * will be thrown.
197      * <p>
198      * @param jMember the JMember to add to this JStructure.
199      * @throws java.lang.IllegalArgumentException when the given
200      * JMember has the same name of an existing JField
201      * or JMethod respectively.
202      */
203     public abstract void addMember( JMember jMember )
204         throws IllegalArgumentException;
205 
206 
207     /**
208      * Adds the given import to this JStructure
209      *
210      * @param the className of the class to import.
211      */
212     public void addImport( String className )
213     {
214         if ( className == null ) return;
215         if ( className.length() == 0 ) return;
216 
217         //-- getPackageName
218         String pkgName = getPackageFromClassName( className );
219 
220         if ( pkgName != null )
221         {
222             if ( pkgName.equals( this.packageName ) ) return;
223 
224             //-- XXX: Fix needed for this...
225             //-- This may cause issues if the current package
226             //-- defines any classes that have the same name
227             //-- name as the java.lang package.
228             if ( "java.lang".equals( pkgName ) ) return;
229 
230             //-- for readabilty keep import list sorted, and make sure
231             //-- we do not include more than one of the same import
232             for ( int i = 0; i < imports.size(); i++ )
233             {
234                 String imp = (String) imports.elementAt( i );
235                 if ( imp.equals( className ) ) return;
236                 if ( imp.compareTo( className ) > 0 )
237                 {
238                     imports.insertElementAt( className, i );
239                     return;
240                 }
241             }
242             imports.addElement( className );
243         }
244     } //-- addImport
245 
246     /**
247      * Adds the given interface to the list of interfaces this
248      * JStructure inherits method declarations from, and either
249      * implements (JClass) or extends (JInterface).
250      *
251      * @param interfaceName the name of the interface to "inherit"
252      * method declarations from.
253      */
254     public void addInterface( String interfaceName )
255     {
256         if ( !interfaces.contains( interfaceName ) )
257             interfaces.addElement( interfaceName );
258     } //-- addInterface
259 
260     /**
261      * Adds the given interface to the list of interfaces this
262      * JStructure inherits method declarations from, and either
263      * implements (JClass) or extends (JInterface).
264      *
265      * @param jInterface the JInterface to inherit from.
266      */
267     public void addInterface( JInterface jInterface )
268     {
269         if ( jInterface == null ) return;
270         String interfaceName = jInterface.getName();
271         if ( !interfaces.contains( interfaceName ) )
272         {
273             interfaces.addElement( interfaceName );
274         }
275     } //-- addInterface
276 
277 
278 
279     /**
280      * Adds the given JMethodSignature to this JClass
281      *
282      * @param jMethodSig the JMethodSignature to add.
283      * @throws java.lang.IllegalArgumentException when the given
284      * JMethodSignature conflicts with an existing
285      * method signature.
286      */
287     /*
288        public void addMethod(JMethodSignature jMethodSig)
289            throws IllegalArgumentException
290        {
291            if (jMethodSig == null) {
292                String err = "The JMethodSignature cannot be null.";
293                throw new IllegalArgumentException(err);
294            }
295 
296            //-- XXXX: check method name and signatures *add later*
297 
298            //-- keep method list sorted for esthetics when printing
299            //-- START SORT :-)
300            boolean added = false;
301            short modifierVal = 0;
302            JModifiers modifiers = jMethodSig.getModifiers();
303            for (int i = 0; i < methods.size(); i++) {
304                JMethodSignature tmp = (JMethodSignature) methods.elementAt(i);
305                //-- first compare modifiers
306                if (tmp.getModifiers().isProtected()) {
307                    if (!modifiers.isProtected()) {
308                        methods.insertElementAt(jMethodSig, i);
309                        added = true;
310                        break;
311                    }
312                }
313                //-- compare names
314                if (jMethodSig.getName().compareTo(tmp.getName()) < 0) {
315                        methods.insertElementAt(jMethodSig, i);
316                        added = true;
317                        break;
318                }
319            }
320            //-- END SORT
321            if (!added) methods.addElement(jMethodSig);
322 
323            //-- check parameter packages to make sure we have them
324            //-- in our import list
325 
326            String[] pkgNames = jMethodSig.getParameterClassNames();
327            for (int i = 0; i < pkgNames.length; i++) {
328                addImport(pkgNames[i]);
329            }
330            //-- check return type to make sure it's included in the
331            //-- import list
332            JType jType = jMethodSig.getReturnType();
333            if (jType != null) {
334                while (jType.isArray())
335                    jType = jType.getComponentType();
336 
337                if   (!jType.isPrimitive())
338                     addImport(jType.getName());
339            }
340            //-- check exceptions
341            JClass[] exceptions = jMethodSig.getExceptions();
342            for (int i = 0; i < exceptions.length; i++) {
343                addImport(exceptions[i].getName());
344            }
345        } //-- addMethod
346    */
347     /**
348      * Returns the field with the given name, or null if no field
349      * was found with the given name.
350      *
351      * @param name the name of the field to return.
352      * @return the field with the given name, or null if no field
353      * was found with the given name.
354      */
355     public abstract JField getField( String name );
356 
357     /**
358      * Returns an array of all the JFields of this JStructure
359      *
360      * @return an array of all the JFields of this JStructure
361      */
362     public abstract JField[] getFields();
363 
364     /**
365      * Returns the name of the file that this JStructure would be
366      * printed to, given a call to #print.
367      *
368      * @param destDir the destination directory. This may be null.
369      * @return the name of the file that this JInterface would be
370      * printed as, given a call to #print.
371      */
372     public String getFilename( String destDir )
373     {
374 
375         String filename = getLocalName() + ".java";
376 
377         //-- Convert Java package to path string
378         String javaPackagePath = "";
379         if ( ( packageName != null ) && ( packageName.length() > 0 ) )
380         {
381             javaPackagePath = packageName.replace( '.', File.separatorChar );
382         }
383 
384         //-- Create fully qualified path (including 'destDir') to file
385         File pathFile;
386         if ( destDir == null )
387             pathFile = new File( javaPackagePath );
388         else
389             pathFile = new File( destDir, javaPackagePath );
390         if ( !pathFile.exists() )
391         {
392             pathFile.mkdirs();
393         }
394 
395         //-- Prefix filename with path
396         if ( pathFile.toString().length() > 0 )
397             filename = pathFile.toString() + File.separator + filename;
398 
399         return filename;
400     } //-- getFilename
401 
402     /**
403      * Returns the JComment header to display at the top of the source file
404      * for this JStructure, or null if no header was set.
405      *
406      * @return the JComment header or null if none exists.
407      */
408     public JComment getHeader()
409     {
410         return this.header;
411     } //-- getHeader
412 
413     /**
414      * Returns an Enumeration of imported package and
415      * class names for this JStructure.
416      *
417      * @return the Enumeration of imports. May be empty.
418      */
419     public Enumeration<String> getImports()
420     {
421         return imports.elements();
422     } //-- getImports
423 
424     /**
425      * Returns an Enumeration of interface names that this
426      * JStructure inherits from.
427      *
428      * @return the Enumeration of interface names for this
429      * JStructure. May be empty.
430      */
431     public Enumeration<String> getInterfaces()
432     {
433         return interfaces.elements();
434     } //-- getInterfaces
435 
436     /**
437      * Returns the Java Doc comment for this JStructure
438      *
439      * @return the JDocComment for this JStructure
440      */
441     public JDocComment getJDocComment()
442     {
443         return jdc;
444     } //-- getJDocComment
445 
446     /**
447      * Returns an array of all the JMethodSignatures of this JInterface.
448      *
449      * @return an array of all the JMethodSignatures of this JInterface.
450      */
451 /*
452     public JMethodSignature[] getMethods() {
453         JMethodSignature[] marray = new JMethodSignature[methods.size()];
454         methods.copyInto(marray);
455         return marray;
456     } //-- getMethods
457 */
458 
459     /**
460      * Returns the JMethodSignature with the given name,
461      * and occuring at or after the given starting index.
462      *
463      * @param name the name of the JMethodSignature to return.
464      * @param startIndex the starting index to begin searching
465      * from.
466      * @return the JMethodSignature, or null if not found.
467      */
468 /*
469     public JMethodSignature getMethod(String name, int startIndex) {
470         for (int i = startIndex; i < methods.size(); i++) {
471             JMethodSignature jMethod = (JMethodSignature)methods.elementAt(i);
472             if (jMethod.getName().equals(name)) return jMethod;
473         }
474         return null;
475     } //-- getMethod
476 */
477 
478     /**
479      * Returns the JMethodSignature at the given index.
480      *
481      * @param index the index of the JMethodSignature to return.
482      * @return the JMethodSignature at the given index.
483      */
484     /*
485        public JMethodSignature getMethod(int index) {
486            return (JMethodSignature)methods.elementAt(index);
487        } //-- getMethod
488     */
489 
490     /**
491      * Returns the JModifiers which allows the qualifiers to be changed.
492      *
493      * @return the JModifiers for this JStructure.
494      */
495     public JModifiers getModifiers()
496     {
497         return modifiers;
498     } //-- getModifiers
499 
500     /**
501      * Returns the name of the package that this JStructure is a member
502      * of.
503      *
504      * @return the name of the package that this JStructure is a member
505      * of, or null if there is no current package name defined.
506      */
507     public String getPackageName()
508     {
509         return this.packageName;
510     } //-- getPackageName
511 
512 
513     /**
514      * Returns the name of the interface.
515      *
516      * @param stripPackage a boolean that when true indicates that only
517      * the local name (no package) should be returned.
518      * @return the name of the class.
519      */
520     public String getName( boolean stripPackage )
521     {
522         String name = super.getName();
523         if ( stripPackage )
524         {
525             int period = name.lastIndexOf( "." );
526             if ( period > 0 )
527                 name = name.substring( period + 1 );
528         }
529         return name;
530     } //-- getName
531 
532     /**
533      * Returns true if the given classname exists in the imports
534      * of this JStructure
535      *
536      * @param classname the class name to check for
537      * @return true if the given classname exists in the imports list
538      */
539     public boolean hasImport( String classname )
540     {
541         return imports.contains( classname );
542     } //-- hasImport
543 
544 
545     public boolean removeImport( String className )
546     {
547         boolean result = false;
548         if ( className == null ) return result;
549         if ( className.length() == 0 ) return result;
550 
551         result = imports.removeElement( className );
552         return result;
553     } //-- removeImport
554 
555 
556     public boolean isAbstract()
557     {
558         return modifiers.isAbstract();
559     }
560 
561     public static boolean isValidClassName( String name )
562     {
563 
564         if ( name == null ) return false;
565 
566         //-- ignore package information, for now
567         int period = name.lastIndexOf( "." );
568         if ( period > 0 )
569             name = name.substring( period + 1 );
570 
571         return JNaming.isValidJavaIdentifier( name );
572     } //-- isValidClassName
573 
574     /**
575      * Prints the source code for this JStructure in the current
576      * working directory. Sub-directories will be created if necessary
577      * for the package.
578      */
579     public void print()
580     {
581         print( (String) null, (String) null );
582     } //-- printSrouce
583 
584     /**
585      * Prints the source code for this JStructure to the destination
586      * directory. Sub-directories will be created if necessary for the
587      * package.
588      *
589      * @param lineSeparator the line separator to use at the end of each line.
590      * If null, then the default line separator for the runtime platform will
591      * be used.
592      */
593     public void print( String destDir, String lineSeparator )
594     {
595 
596 //        String name = getLocalName();
597 
598         //-- open output file
599         String filename = getFilename( destDir );
600 
601         File file = new File( filename );
602         JSourceWriter jsw = null;
603         try
604         {
605             jsw = new JSourceWriter( WriterFactory.newPlatformWriter( file ) );
606         }
607         catch ( java.io.IOException ioe )
608         {
609             System.out.println( "unable to create class file: " + filename );
610             return;
611         }
612         if ( lineSeparator == null )
613         {
614             lineSeparator = System.getProperty( "line.separator" );
615         }
616         jsw.setLineSeparator( lineSeparator );
617         print( jsw );
618         jsw.close();
619 
620     } //-- print
621 
622     /**
623      * Prints the source code for this JStructure to the given
624      * JSourceWriter.
625      *
626      * @param jsw the JSourceWriter to print to.
627      */
628     public abstract void print( JSourceWriter jsw );
629 
630     /**
631      * A utility method that prints the header to the given
632      * JSourceWriter
633      *
634      * @param jsw the JSourceWriter to print to.
635      */
636     public void printHeader( JSourceWriter jsw )
637     {
638 
639         if ( jsw == null )
640         {
641             throw new IllegalArgumentException( "argument 'jsw' should not be null." );
642         }
643 
644         //-- write class header
645         JComment header = getHeader();
646         if ( header != null )
647             header.print( jsw );
648         else
649         {
650             jsw.writeln( "/*" );
651             jsw.writeln( " * " + DEFAULT_HEADER );
652             jsw.writeln( " */" );
653         }
654         jsw.writeln();
655         jsw.flush();
656     } //-- printHeader
657 
658     /**
659      * A utility method that prints the imports to the given
660      * JSourceWriter
661      *
662      * @param jsw the JSourceWriter to print to.
663      */
664     public void printImportDeclarations( JSourceWriter jsw )
665     {
666 
667         if ( jsw == null )
668         {
669             throw new IllegalArgumentException( "argument 'jsw' should not be null." );
670         }
671 
672         //-- print imports
673         if ( imports.size() > 0 )
674         {
675             jsw.writeln( "  //---------------------------------/" );
676             jsw.writeln( " //- Imported classes and packages -/" );
677             jsw.writeln( "//---------------------------------/" );
678             jsw.writeln();
679             Enumeration<String> e = imports.elements();
680             while ( e.hasMoreElements() )
681             {
682                 jsw.write( "import " );
683                 jsw.write( e.nextElement() );
684                 jsw.writeln( ';' );
685             }
686             jsw.writeln();
687             jsw.flush();
688         }
689     } //-- printImportDeclarations
690 
691     /**
692      * A utility method that prints the packageDeclaration to
693      * the given JSourceWriter
694      *
695      * @param jsw the JSourceWriter to print to.
696      */
697     public void printPackageDeclaration( JSourceWriter jsw )
698     {
699 
700         if ( jsw == null )
701         {
702             throw new IllegalArgumentException( "argument 'jsw' should not be null." );
703         }
704 
705         //-- print package name
706         if ( ( packageName != null ) && ( packageName.length() > 0 ) )
707         {
708             jsw.write( "package " );
709             jsw.write( packageName );
710             jsw.writeln( ';' );
711             jsw.writeln();
712         }
713         jsw.flush();
714     } //-- printPackageDeclaration
715 
716     /**
717      * Prints the source code for this JStructure to the given
718      * JSourceWriter.
719      *
720      * @param jsw the JSourceWriter to print to.
721      *
722      public abstract void print(JSourceWriter jsw);
723 
724 
725      StringBuffer buffer = new StringBuffer();
726 
727 
728      printHeader();
729      printPackageDeclaration();
730      printImportDeclarations();
731 
732      //------------/
733      //- Java Doc -/
734      //------------/
735 
736      jdc.print(jsw);
737 
738      //-- print class information
739      //-- we need to add some JavaDoc API adding comments
740 
741      buffer.setLength(0);
742 
743      if (modifiers.isPrivate()) {
744      buffer.append("private ");
745      }
746      else if (modifiers.isPublic()) {
747      buffer.append("public ");
748      }
749 
750      if (modifiers.isAbstract()) {
751      buffer.append("abstract ");
752      }
753 
754      buffer.append("interface ");
755      buffer.append(getLocalName());
756      buffer.append(' ');
757      if (interfaces.size() > 0) {
758      boolean endl = false;
759      if (interfaces.size() > 1) {
760      jsw.writeln(buffer.toString());
761      buffer.setLength(0);
762      endl = true;
763      }
764      buffer.append("extends ");
765      for (int i = 0; i < interfaces.size(); i++) {
766      if (i > 0) buffer.append(", ");
767      buffer.append(interfaces.elementAt(i));
768      }
769      if (endl) {
770      jsw.writeln(buffer.toString());
771      buffer.setLength(0);
772      }
773      else buffer.append(' ');
774      }
775 
776      buffer.append('{');
777      jsw.writeln(buffer.toString());
778      buffer.setLength(0);
779      jsw.writeln();
780 
781      jsw.indent();
782 
783      //-- print method signatures
784 
785      if (methods.size() > 0) {
786      jsw.writeln();
787      jsw.writeln("  //-----------/");
788      jsw.writeln(" //- Methods -/");
789      jsw.writeln("//-----------/");
790      jsw.writeln();
791      }
792 
793      for (int i = 0; i < methods.size(); i++) {
794      JMethodSignature signature = (JMethodSignature) methods.elementAt(i);
795      signature.print(jsw);
796      jsw.writeln(';');
797      }
798 
799      jsw.unindent();
800      jsw.writeln('}');
801      jsw.flush();
802      jsw.close();
803      } //-- printSource
804      */
805 
806     /**
807      * Sets the header comment for this JStructure
808      *
809      * @param comment the comment to display at the top of the source file
810      * when printed
811      */
812     public void setHeader( JComment comment )
813     {
814         this.header = comment;
815     } //-- setHeader
816 
817     /**
818      * Allows changing the package name of this JStructure
819      *
820      * @param packageName the package name to use
821      * @deprecated removed in future version of javasource
822      */
823     public void setPackageName( String packageName )
824     {
825         this.packageName = packageName;
826         changePackage( packageName );
827     } //-- setPackageName
828 
829 
830     //---------------------/
831     //- Protected Methods -/
832     //---------------------/
833 
834     protected int getInterfaceCount()
835     {
836         return interfaces.size();
837     }
838 
839     /**
840      * Prints the given source string to the JSourceWriter using the given prefix at
841      * the beginning of each new line.
842      *
843      * @param prefix the prefix for each new line.
844      * @param source the source code to print
845      * @param jsw the JSourceWriter to print to.
846      */
847     protected static void printlnWithPrefix( String prefix, String source, JSourceWriter jsw )
848     {
849         jsw.write( prefix );
850         if ( source == null ) return;
851 
852         char[] chars = source.toCharArray();
853         int lastIdx = 0;
854         for ( int i = 0; i < chars.length; i++ )
855         {
856             char ch = chars[i];
857             if ( ch == '\n' )
858             {
859                 //-- free buffer
860                 jsw.write( chars, lastIdx, ( i - lastIdx ) + 1 );
861                 lastIdx = i + 1;
862                 if ( i < chars.length )
863                 {
864                     jsw.write( prefix );
865                 }
866             }
867         }
868         //-- free buffer
869         if ( lastIdx < chars.length )
870         {
871             jsw.write( chars, lastIdx, chars.length - lastIdx );
872         }
873         jsw.writeln();
874 
875     } //-- printlnWithPrefix
876 
877 
878     /**
879      * Returns the package name from the given class name
880      */
881     protected static String getPackageFromClassName( String className )
882     {
883         int idx = -1;
884         if ( ( idx = className.lastIndexOf( '.' ) ) > 0 )
885         {
886             return className.substring( 0, idx );
887         }
888         return null;
889     } //-- getPackageFromClassName
890 
891     /**
892      * @return the annotations
893      */
894     public JAnnotations getAnnotations()
895     {
896         return annotations;
897     }
898 
899     /**
900      * @param annotation the annotation to append
901      */
902     public void appendAnnotation( String annotation )
903     {
904         if ( annotations == null )
905         {
906             annotations = new JAnnotations();
907         }
908         annotations.appendAnnotation( annotation );
909     }
910 
911     /**
912      * @param annotations the annotations to set
913      */
914     public void setAnnotations( JAnnotations annotations )
915     {
916         this.annotations = annotations;
917     }
918 
919 } //-- JStructure