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