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  package org.codehaus.modello.plugin.java.javasource;
46  
47  /*
48   * Copyright (c) 2004, Codehaus.org
49   *
50   * Permission is hereby granted, free of charge, to any person obtaining a copy of
51   * this software and associated documentation files (the "Software"), to deal in
52   * the Software without restriction, including without limitation the rights to
53   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
54   * of the Software, and to permit persons to whom the Software is furnished to do
55   * so, subject to the following conditions:
56   *
57   * The above copyright notice and this permission notice shall be included in all
58   * copies or substantial portions of the Software.
59   *
60   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66   * SOFTWARE.
67   */
68  
69  import java.util.ArrayList;
70  import java.util.Enumeration;
71  import java.util.LinkedHashMap;
72  import java.util.List;
73  import java.util.Map;
74  
75  /**
76   * A representation of the Java Source code for a Java Interface.
77   * This is a useful utility when creating in memory source code.
78   * The code in this package was modelled after the Java Reflection API
79   * as much as possible to reduce the learning curve.
80   *
81   * @author <a href="mailto:skopp@riege.de">Martin Skopp</a>
82   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
83   * @version $Revision$ $Date$
84   **/
85  public final class JInterface extends JStructure {
86  
87      /**
88       * The fields for this JInterface
89       */
90      private Map<String, JField> fields = null;
91  
92      /**
93       * The list of methods of this JInterface
94       */
95      private List<JMethodSignature> methods = null;
96  
97      /**
98       * Creates a new JInterface with the given name.
99       *
100      * @param name the name of the JInterface.
101      * @throws java.lang.IllegalArgumentException when the given name
102      * is not a valid Class name.
103      **/
104     public JInterface(String name) throws IllegalArgumentException {
105         super(name);
106         methods = new ArrayList<JMethodSignature>();
107 
108         // -- initialize default Java doc
109         getJDocComment().appendComment("Interface " + getLocalName() + ".");
110     } // -- JInterface
111 
112     /**
113      * Adds the given JField to this JStructure.
114      * <p>
115      * This method is implemented by subclasses and
116      * should only accept the proper fields for the
117      * subclass otherwise an IllegalArgumentException
118      * will be thrown. For example a JInterface will
119      * only accept static fields.
120      * <p>
121      * @param jField, the JField to add
122      * @exception java.lang.IllegalArgumentException when the given
123      * JField has a name of an existing JField
124      */
125     public void addField(JField jField) throws IllegalArgumentException {
126         if (jField == null) {
127             throw new IllegalArgumentException("argument 'jField' cannot be null");
128         }
129 
130         String name = jField.getName();
131 
132         // -- check for duplicate field name
133         if ((fields != null) && (fields.get(name) != null)) {
134             String err = "duplicate name found: " + name;
135             throw new IllegalArgumentException(err);
136         }
137 
138         // -- check for proper modifiers
139         JModifiers modifiers = jField.getModifiers();
140         if (!modifiers.isStatic()) {
141             throw new IllegalArgumentException("Fields added to a JInterface must be static.");
142         }
143         if (modifiers.isPrivate()) {
144             throw new IllegalArgumentException("Fields added to a JInterface must not be private.");
145         }
146 
147         // -- only initialize fields if we need it, many interfaces
148         // -- don't contain any fields, no need to waste space
149         if (fields == null) {
150             fields = new LinkedHashMap<>(3);
151         }
152 
153         fields.put(name, jField);
154     }
155 
156     /**
157      * Adds the given JMember to this JStructure.
158      * <p>
159      * This method is implemented by subclasses and
160      * should only accept the proper types for the
161      * subclass otherwise an IllegalArgumentException
162      * will be thrown.
163      * <p>
164      * @param jMember the JMember to add to this JStructure.
165      * @throws java.lang.IllegalArgumentException when the given
166      * JMember has the same name of an existing JField
167      * or JMethod respectively.
168      */
169     public void addMember(JMember jMember) throws IllegalArgumentException {
170         if (jMember == null) {
171             throw new IllegalArgumentException("argument 'jMember' may not be null.");
172         }
173         if (jMember instanceof JField) {
174             addField((JField) jMember);
175         } else {
176             throw new IllegalArgumentException("invalid member for JInterface: " + jMember.toString());
177         }
178     } // -- addMember
179 
180     /**
181      * Adds the given JMethodSignature to this JClass
182      *
183      * @param jMethodSig the JMethodSignature to add.
184      * @throws java.lang.IllegalArgumentException when the given
185      * JMethodSignature conflicts with an existing
186      * method signature.
187      */
188     public void addMethod(JMethodSignature jMethodSig) throws IllegalArgumentException {
189         if (jMethodSig == null) {
190             String err = "The JMethodSignature cannot be null.";
191             throw new IllegalArgumentException(err);
192         }
193 
194         // -- check method name and signatures *add later*
195 
196         // -- keep method list sorted for esthetics when printing
197         // -- START SORT :-)
198         boolean added = false;
199         //        short modifierVal = 0;
200         JModifiers modifiers = jMethodSig.getModifiers();
201         for (int i = 0; i < methods.size(); i++) {
202             JMethodSignature tmp = methods.get(i);
203             // -- first compare modifiers
204             if (tmp.getModifiers().isProtected()) {
205                 if (!modifiers.isProtected()) {
206                     methods.add(i, jMethodSig);
207                     added = true;
208                     break;
209                 }
210             }
211             // -- compare names
212             if (jMethodSig.getName().compareTo(tmp.getName()) < 0) {
213                 methods.add(i, jMethodSig);
214                 added = true;
215                 break;
216             }
217         }
218         // -- END SORT
219         if (!added) methods.add(jMethodSig);
220 
221         // -- check return type to make sure it's included in the
222         // -- import list
223         JType jType = jMethodSig.getReturnType();
224         if (jType != null) {
225             while (jType.isArray()) jType = jType.getComponentType();
226 
227             if (!jType.isPrimitive()) addImport(jType.getName());
228         }
229         // -- check exceptions
230         JClass[] exceptions = jMethodSig.getExceptions();
231         for (JClass exception : exceptions) {
232             addImport(exception.getName());
233         }
234     } // -- addMethod
235 
236     /**
237      * Returns the field with the given name, or null if no field
238      * was found with the given name.
239      *
240      * @param name the name of the field to return.
241      * @return the field with the given name, or null if no field
242      * was found with the given name.
243      */
244     public JField getField(String name) {
245         if (fields == null) return null;
246         return (JField) fields.get(name);
247     } // -- getField
248 
249     /**
250      * Returns an array of all the JFields of this JStructure
251      *
252      * @return an array of all the JFields of this JStructure
253      */
254     public JField[] getFields() {
255         if (fields == null) {
256             return new JField[0];
257         }
258         return fields.values().toArray(new JField[0]);
259     } // -- getFields
260 
261     /**
262      * Returns an array of all the JMethodSignatures of this JInterface.
263      *
264      * @return an array of all the JMethodSignatures of this JInterface.
265      **/
266     public JMethodSignature[] getMethods() {
267         return methods.toArray(new JMethodSignature[0]);
268     } // -- getMethods
269 
270     /**
271      * Returns the JMethodSignature with the given name,
272      * and occuring at or after the given starting index.
273      *
274      * @param name the name of the JMethodSignature to return.
275      * @param startIndex the starting index to begin searching
276      * from.
277      * @return the JMethodSignature, or null if not found.
278      **/
279     public JMethodSignature getMethod(String name, int startIndex) {
280         for (JMethodSignature jMethod : methods) {
281             if (jMethod.getName().equals(name)) return jMethod;
282         }
283         return null;
284     } // -- getMethod
285 
286     /**
287      * Returns the JMethodSignature at the given index.
288      *
289      * @param index the index of the JMethodSignature to return.
290      * @return the JMethodSignature at the given index.
291      **/
292     public JMethodSignature getMethod(int index) {
293         return methods.get(index);
294     } // -- getMethod
295 
296     /**
297      * Prints the source code for this JInterface to the given JSourceWriter
298      *
299      * @param jsw the JSourceWriter to print to. [May not be null]
300      */
301     public void print(JSourceWriter jsw) {
302         print(jsw, false);
303     }
304 
305     /**
306      * Prints the source code for this JInterface to the given JSourceWriter
307      *
308      * @param jsw the JSourceWriter to print to. [May not be null]
309      * @param classOnly whether the header, package and imports should be printed too
310      */
311     public void print(JSourceWriter jsw, boolean classOnly) {
312 
313         if (jsw == null) {
314             throw new IllegalArgumentException("argument 'jsw' should not be null.");
315         }
316 
317         StringBuilder buffer = new StringBuilder();
318 
319         if (!classOnly) {
320             printHeader(jsw);
321             printPackageDeclaration(jsw);
322             printImportDeclarations(jsw);
323         }
324 
325         // ------------/
326         // - Java Doc -/
327         // ------------/
328 
329         getJDocComment().print(jsw);
330 
331         JAnnotations annotations = getAnnotations();
332         if (annotations != null) annotations.print(jsw);
333 
334         // -- print class information
335         // -- we need to add some JavaDoc API adding comments
336 
337         buffer.setLength(0);
338 
339         JModifiers modifiers = getModifiers();
340         if (modifiers.isPrivate()) {
341             buffer.append("private ");
342         } else if (modifiers.isPublic()) {
343             buffer.append("public ");
344         }
345 
346         if (modifiers.isAbstract()) {
347             buffer.append("abstract ");
348         }
349 
350         buffer.append("interface ");
351         buffer.append(getLocalName());
352         jsw.writeln(buffer.toString());
353         buffer.setLength(0);
354         jsw.indent();
355 
356         if (getInterfaceCount() > 0) {
357             Enumeration<String> e = getInterfaces();
358             buffer.append("extends ");
359             while (e.hasMoreElements()) {
360                 buffer.append(e.nextElement());
361                 if (e.hasMoreElements()) buffer.append(", ");
362             }
363 
364             jsw.writeln(buffer.toString());
365             buffer.setLength(0);
366         }
367 
368         jsw.unindent();
369 
370         jsw.writeln('{');
371 
372         jsw.indent();
373 
374         // -- declare static members
375 
376         if (fields != null) {
377             if (fields.size() > 0) {
378                 jsw.writeln();
379                 jsw.writeln("  //--------------------------/");
380                 jsw.writeln(" //- Class/Member Variables -/");
381                 jsw.writeln("//--------------------------/");
382                 jsw.writeln();
383             }
384 
385             for (JField jField : fields.values()) {
386                 // -- print Java comment
387                 JDocComment comment = jField.getComment();
388                 if (comment != null) comment.print(jsw);
389 
390                 // -- print member
391                 jsw.write(jField.getModifiers().toString());
392                 jsw.write(' ');
393 
394                 JType type = jField.getType();
395                 String typeName = type.toString();
396                 // -- for esthetics use short name in some cases
397                 if (typeName.equals(toString())) {
398                     typeName = type.getLocalName();
399                 }
400                 jsw.write(typeName);
401                 jsw.write(' ');
402                 jsw.write(jField.getName());
403 
404                 String init = jField.getInitString();
405                 if (init != null) {
406                     jsw.write(" = ");
407                     jsw.write(init);
408                 }
409 
410                 jsw.writeln(';');
411                 jsw.writeln();
412             }
413         }
414 
415         // -- print method signatures
416 
417         if (methods.size() > 0) {
418             jsw.writeln();
419             jsw.writeln("  //-----------/");
420             jsw.writeln(" //- Methods -/");
421             jsw.writeln("//-----------/");
422             jsw.writeln();
423         }
424 
425         for (JMethodSignature signature : methods) {
426             signature.print(jsw);
427             jsw.writeln(';');
428         }
429 
430         for (String sourceCodeEntry : sourceCodeEntries) {
431             jsw.writeln(sourceCodeEntry);
432         }
433 
434         jsw.unindent();
435         jsw.writeln('}');
436         jsw.flush();
437         jsw.close();
438     } // -- printSource
439 
440     private List<String> sourceCodeEntries = new ArrayList<String>();
441 
442     public void addSourceCode(String sourceCode) {
443         sourceCodeEntries.add(sourceCode);
444     }
445 } // -- JInterface