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 className 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 destDir the destination directory
590      * @param lineSeparator the line separator to use at the end of each line.
591      * If null, then the default line separator for the runtime platform will
592      * be used.
593      */
594     public void print( String destDir, String lineSeparator )
595     {
596 
597 //        String name = getLocalName();
598 
599         //-- open output file
600         String filename = getFilename( destDir );
601 
602         File file = new File( filename );
603         JSourceWriter jsw = null;
604         try
605         {
606             jsw = new JSourceWriter( WriterFactory.newPlatformWriter( file ) );
607         }
608         catch ( java.io.IOException ioe )
609         {
610             System.out.println( "unable to create class file: " + filename );
611             return;
612         }
613         if ( lineSeparator == null )
614         {
615             lineSeparator = System.getProperty( "line.separator" );
616         }
617         jsw.setLineSeparator( lineSeparator );
618         print( jsw );
619         jsw.close();
620 
621     } //-- print
622 
623     /**
624      * Prints the source code for this JStructure to the given
625      * JSourceWriter.
626      *
627      * @param jsw the JSourceWriter to print to.
628      */
629     public abstract void print( JSourceWriter jsw );
630 
631     /**
632      * A utility method that prints the header to the given
633      * JSourceWriter
634      *
635      * @param jsw the JSourceWriter to print to.
636      */
637     public void printHeader( JSourceWriter jsw )
638     {
639 
640         if ( jsw == null )
641         {
642             throw new IllegalArgumentException( "argument 'jsw' should not be null." );
643         }
644 
645         //-- write class header
646         JComment header = getHeader();
647         if ( header != null )
648             header.print( jsw );
649         else
650         {
651             jsw.writeln( "/*" );
652             jsw.writeln( " * " + DEFAULT_HEADER );
653             jsw.writeln( " */" );
654         }
655         jsw.writeln();
656         jsw.flush();
657     } //-- printHeader
658 
659     /**
660      * A utility method that prints the imports to the given
661      * JSourceWriter
662      *
663      * @param jsw the JSourceWriter to print to.
664      */
665     public void printImportDeclarations( JSourceWriter jsw )
666     {
667 
668         if ( jsw == null )
669         {
670             throw new IllegalArgumentException( "argument 'jsw' should not be null." );
671         }
672 
673         //-- print imports
674         if ( imports.size() > 0 )
675         {
676             jsw.writeln( "  //---------------------------------/" );
677             jsw.writeln( " //- Imported classes and packages -/" );
678             jsw.writeln( "//---------------------------------/" );
679             jsw.writeln();
680             Enumeration<String> e = imports.elements();
681             while ( e.hasMoreElements() )
682             {
683                 jsw.write( "import " );
684                 jsw.write( e.nextElement() );
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      StringBuffer buffer = new StringBuffer();
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