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@exolab.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.exolab.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  package org.exolab.javasource;
44  
45  import java.util.Enumeration;
46  import java.util.LinkedHashMap;
47  import java.util.Map;
48  import java.util.Vector;
49  
50  /**
51   * A representation of the Java Source code for a Java Interface. This is a
52   * useful utility when creating in memory source code. The code in this package
53   * was modeled after the Java Reflection API as much as possible to reduce the
54   * learning curve.
55   *
56   * @author <a href="mailto:skopp AT riege DOT de">Martin Skopp</a>
57   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
58   * @version $Revision$ $Date: 2005-02-26 17:30:28 -0700 (Sat, 26 Feb 2005) $
59   */
60  public final class JInterface extends JStructure {
61  
62      /** The fields for this JInterface. */
63      private Map<String, JField> _fields = new LinkedHashMap<String, JField>();
64      
65      /** The list of methods of this JInterface. */
66      private Vector<JMethodSignature> _methods;
67  
68      /**
69       * Creates a new JInterface with the given name.
70       *
71       * @param name The name of the JInterface.
72       */
73      public JInterface(final String name) {
74          super(name);
75          
76          _methods = new Vector<JMethodSignature>();
77  
78          //-- initialize default Java doc
79          getJDocComment().appendComment("Interface " + getLocalName() + ".");
80      }
81  
82      /**
83       * {@inheritDoc}
84       */
85      public void addImport(final String className) {
86          if (className == null || className.length() == 0) { return; }
87          addImportInternal(className);
88      }
89  
90      /**
91       * Adds the given JMember to this Jinterface.
92       * <p>
93       * This method is implemented by subclasses and should only accept the
94       * proper types for the subclass otherwise an IllegalArgumentException will
95       * be thrown.
96       *
97       * @param jMember The JMember to add to this JStructure.
98       */
99      public void addMember(final JMember jMember) {
100         if (jMember == null) {
101             throw new IllegalArgumentException("argument 'jMember' may not be null.");
102         }
103         if (jMember instanceof JField) {
104             addField((JField) jMember);
105         } else {
106             throw new IllegalArgumentException("invalid member for JInterface: "
107                     + jMember.toString());
108         }
109     }
110 
111     /**
112      * Returns an array of all the JFields of this Jinterface.
113      *
114      * @return An array of all the JFields of this Jinterface.
115      */
116     public JField[] getFields() {
117         return _fields.values().toArray(new JField[_fields.size()]);
118     }
119 
120     /**
121      * Returns the field with the given name, or null if no field was found with
122      * the given name.
123      *
124      * @param name The name of the field to return.
125      * @return The field with the given name, or null if no field was found with
126      *         the given name.
127      */
128     public JField getField(final String name) {
129         return _fields.get(name);
130     }
131 
132     /**
133      * Adds the given JField to this Jinterface.
134      * <p>
135      * This method is implemented by subclasses and should only accept the
136      * proper fields for the subclass otherwise an IllegalArgumentException will
137      * be thrown. For example a JInterface will only accept static fields.
138      *
139      * @param jField The JField to add.
140      */
141     public void addField(final JField jField) {
142         if (jField == null) {
143             throw new IllegalArgumentException("argument 'jField' cannot be null");
144         }
145 
146         String name = jField.getName();
147 
148         //-- check for duplicate field name
149         if ((_fields != null) && (_fields.get(name) != null)) {
150             String err = "duplicate name found: " + name;
151             throw new IllegalArgumentException(err);
152         }
153 
154         //-- check for proper modifiers
155         JModifiers modifiers = jField.getModifiers();
156         if (!modifiers.isStatic()) {
157             String err = "Fields added to a JInterface must be static.";
158             throw new IllegalArgumentException(err);
159         }
160         if (modifiers.isPrivate()) {
161             String err = "Fields added to a JInterface must not be private.";
162             throw new IllegalArgumentException(err);
163         }
164 
165         _fields.put(name, jField);
166 
167         // if member is of a type not imported by this class
168         // then add import
169         JType type = jField.getType();
170         while (type.isArray()) {
171             type = ((JArrayType) type).getComponentType();
172         }
173         if (!type.isPrimitive()) {
174             addImport(((JClass) type).getName());
175         }
176 
177         // ensure annotation classes are imported
178         addImport(jField.getAnnotations());
179     }
180 
181     /**
182      * Returns an array of all the JMethodSignatures of this JInterface.
183      *
184      * @return An array of all the JMethodSignatures of this JInterface.
185      */
186     public JMethodSignature[] getMethods() {
187         JMethodSignature[] marray = new JMethodSignature[_methods.size()];
188         _methods.copyInto(marray);
189         return marray;
190     }
191 
192     /**
193      * Returns the JMethodSignature with the given name and occuring at or
194      * after the given starting index.
195      *
196      * @param name The name of the JMethodSignature to return.
197      * @param startIndex The starting index to begin searching from.
198      * @return The JMethodSignature, or null if not found.
199      */
200     public JMethodSignature getMethod(final String name, final int startIndex) {
201         for (int i = startIndex; i < _methods.size(); i++) {
202             JMethodSignature jMethod = _methods.elementAt(i);
203             if (jMethod.getName().equals(name)) { return jMethod; }
204         }
205         return null;
206     }
207 
208     /**
209      * Returns the JMethodSignature at the given index.
210      *
211      * @param index The index of the JMethodSignature to return.
212      * @return The JMethodSignature at the given index.
213      */
214     public JMethodSignature getMethod(final int index) {
215         return _methods.elementAt(index);
216     }
217 
218     /**
219      * Adds the given JMethodSignature to this Jinterface.
220      *
221      * @param jMethodSig The JMethodSignature to add.
222      */
223     public void addMethod(final JMethodSignature jMethodSig) {
224         if (jMethodSig == null) {
225             String err = "The JMethodSignature cannot be null.";
226             throw new IllegalArgumentException(err);
227         }
228 
229         //-- check method name and signatures *add later*
230 
231         //-- keep method list sorted for esthetics when printing
232         //-- START SORT :-)
233         boolean added = false;
234         JModifiers modifiers = jMethodSig.getModifiers();
235         for (int i = 0; i < _methods.size(); i++) {
236             JMethodSignature tmp = _methods.elementAt(i);
237             //-- first compare modifiers
238             if (tmp.getModifiers().isProtected() && !modifiers.isProtected()) {
239                 _methods.insertElementAt(jMethodSig, i);
240                 added = true;
241                 break;
242             }
243             //-- compare names
244             if (jMethodSig.getName().compareTo(tmp.getName()) < 0) {
245                 _methods.insertElementAt(jMethodSig, i);
246                 added = true;
247                 break;
248             }
249         }
250         //-- END SORT
251         if (!added) { _methods.addElement(jMethodSig); }
252 
253         //-- check parameter packages to make sure we have them
254         //-- in our import list
255 
256         String[] pkgNames = jMethodSig.getParameterClassNames();
257         for (int i = 0; i < pkgNames.length; i++) {
258             addImport(pkgNames[i]);
259         }
260         //-- check return type to make sure it's included in the
261         //-- import list
262         JType jType = jMethodSig.getReturnType();
263         if (jType != null) {
264             while (jType.isArray()) {
265                 jType = ((JArrayType) jType).getComponentType();
266             }
267             if (!jType.isPrimitive()) {
268                 addImport(jType.getName());
269             }
270         }
271         //-- check exceptions
272         JClass[] exceptions = jMethodSig.getExceptions();
273         for (int i = 0; i < exceptions.length; i++) {
274             addImport(exceptions[i].getName());
275         }
276         //-- ensure method and parameter annotations imported
277         addImport(jMethodSig.getAnnotations());
278         JParameter[] params = jMethodSig.getParameters();
279         for (int i = 0; i < params.length; i++) {
280             addImport(params[i].getAnnotations());
281         }
282     }
283 
284     /**
285      * {@inheritDoc}
286      * 
287      * @deprecated Please use the Velocity-template based approach instead.
288      * @see SourceGenerator#setJClassPrinterType(String) 
289      */
290     public void print(final JSourceWriter jsw) {
291         print(jsw, false);
292     }
293 
294     /**
295      * Prints the source code for this JInterface to the given JSourceWriter.
296      *
297      * @param jsw The JSourceWriter to print to. Must not be null.
298      * @param classOnly If true, generates the class body without the class
299      *            header, package declaration, or imports.
300      *            
301      * @deprecated Please use the Velocity-template based approach instead.
302      * @see SourceGenerator#setJClassPrinterType(String) 
303      */
304     public void print(final JSourceWriter jsw, final boolean classOnly) {
305         if (jsw == null) {
306             throw new IllegalArgumentException("argument 'jsw' should not be null.");
307         }
308 
309         StringBuilder buffer = new StringBuilder(100);
310 
311         if (!classOnly) {
312             printHeader(jsw);
313             printPackageDeclaration(jsw);
314             printImportDeclarations(jsw);
315         }
316 
317         getJDocComment().print(jsw);
318 
319         getAnnotatedElementHelper().printAnnotations(jsw);
320 
321         buffer.setLength(0);
322 
323         JModifiers modifiers = getModifiers();
324         if (modifiers.isPrivate()) {
325             buffer.append("private ");
326         } else if (modifiers.isPublic()) {
327             buffer.append("public ");
328         }
329 
330         if (modifiers.isAbstract()) {
331             buffer.append("abstract ");
332         }
333 
334         buffer.append("interface ");
335         buffer.append(getLocalName());
336         buffer.append(' ');
337         if (getInterfaceCount() > 0) {
338             Enumeration<String> enumeration = getInterfaces();
339             boolean endl = false;
340             if (getInterfaceCount() > 1) {
341                 jsw.writeln(buffer.toString());
342                 buffer.setLength(0);
343                 endl = true;
344             }
345             buffer.append("extends ");
346             while (enumeration.hasMoreElements()) {
347                 buffer.append(enumeration.nextElement());
348                 if (enumeration.hasMoreElements()) { buffer.append(", "); }
349             }
350             if (endl) {
351                 jsw.writeln(buffer.toString());
352                 buffer.setLength(0);
353             } else {
354                 buffer.append(' ');
355             }
356         }
357 
358         buffer.append('{');
359         jsw.writeln(buffer.toString());
360         buffer.setLength(0);
361         jsw.writeln();
362 
363         jsw.indent();
364 
365         //-- declare static members
366 
367         if (!_fields.isEmpty()) {
368             jsw.writeln();
369             jsw.writeln("  //--------------------------/");
370             jsw.writeln(" //- Class/Member Variables -/");
371             jsw.writeln("//--------------------------/");
372             jsw.writeln();
373         }
374 
375         for (JField jField : _fields.values()) {
376 
377             //-- print Java comment
378             JDocComment comment = jField.getComment();
379             if (comment != null) { comment.print(jsw); }
380 
381             // -- annotations
382             jField.printAnnotations(jsw);
383 
384             // -- print member
385             jsw.write(jField.getModifiers().toString());
386             jsw.write(' ');
387 
388             JType type = jField.getType();
389             String typeName = type.toString();
390             //-- for esthetics use short name in some cases
391             if (typeName.equals(toString())) {
392                 typeName = type.getLocalName();
393             }
394             jsw.write(typeName);
395             jsw.write(' ');
396             jsw.write(jField.getName());
397 
398             String init = jField.getInitString();
399             if (init != null) {
400                 jsw.write(" = ");
401                 jsw.write(init);
402             }
403 
404             jsw.writeln(';');
405             jsw.writeln();
406         }
407 
408         //-- print method signatures
409 
410         if (_methods.size() > 0) {
411             jsw.writeln();
412             jsw.writeln("  //-----------/");
413             jsw.writeln(" //- Methods -/");
414             jsw.writeln("//-----------/");
415             jsw.writeln();
416         }
417 
418         for (int i = 0; i < _methods.size(); i++) {
419             JMethodSignature signature = _methods.elementAt(i);
420             signature.print(jsw);
421             jsw.writeln(';');
422         }
423 
424         jsw.unindent();
425         jsw.writeln('}');
426         jsw.flush();
427         jsw.close();
428     }
429 
430 }