View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2001-2002 (C) Intalio, Inc. All Rights Reserved.
32   */
33  package org.exolab.javasource;
34  
35  import java.util.Enumeration;
36  import java.util.LinkedHashMap;
37  import java.util.Map;
38  import java.util.Vector;
39  
40  /**
41   * A representation of the Java Source code for a Java Interface. This is a useful utility when
42   * creating in memory source code. The code in this package was modeled after the Java Reflection
43   * API as much as possible to reduce the learning curve.
44   *
45   * @author <a href="mailto:skopp AT riege DOT de">Martin Skopp</a>
46   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
47   * @version $Revision$ $Date: 2005-02-26 17:30:28 -0700 (Sat, 26 Feb 2005) $
48   */
49  public final class JInterface extends JStructure {
50  
51    /** The fields for this JInterface. */
52    private final Map<String, JField> _fields = new LinkedHashMap<String, JField>();
53  
54    /** The list of methods of this JInterface. */
55    private final Vector<JMethodSignature> _methods = new Vector<JMethodSignature>();
56  
57    /**
58     * Creates a new JInterface with the given name.
59     *
60     * @param name The name of the JInterface.
61     */
62    public JInterface(final String name) {
63      super(name);
64  
65      // -- initialize default Java doc
66      getJDocComment().appendComment("Interface " + getLocalName() + ".");
67    }
68  
69    /**
70     * {@inheritDoc}
71     */
72    public void addImport(final String className) {
73      if (className == null || className.isEmpty()) {
74        return;
75      }
76      addImportInternal(className);
77    }
78  
79    /**
80     * Adds the given JMember to this Jinterface.
81     * <p>
82     * This method is implemented by subclasses and should only accept the proper types for the
83     * subclass otherwise an IllegalArgumentException will be thrown.
84     *
85     * @param jMember The JMember to add to this JStructure.
86     */
87    public void addMember(final JMember jMember) {
88      if (jMember == null) {
89        throw new IllegalArgumentException("argument 'jMember' may not be null.");
90      }
91      if (jMember instanceof JField) {
92        addField((JField) jMember);
93      } else {
94        throw new IllegalArgumentException("invalid member for JInterface: " + jMember);
95      }
96    }
97  
98    /**
99     * Returns an array of all the JFields of this Jinterface.
100    *
101    * @return An array of all the JFields of this Jinterface.
102    */
103   public JField[] getFields() {
104     return _fields.values().toArray(new JField[_fields.size()]);
105   }
106 
107   /**
108    * Returns the field with the given name, or null if no field was found with the given name.
109    *
110    * @param name The name of the field to return.
111    * @return The field with the given name, or null if no field was found with the given name.
112    */
113   public JField getField(final String name) {
114     return _fields.get(name);
115   }
116 
117   /**
118    * Adds the given JField to this Jinterface.
119    * <p>
120    * This method is implemented by subclasses and should only accept the proper fields for the
121    * subclass otherwise an IllegalArgumentException will be thrown. For example a JInterface will
122    * only accept static fields.
123    *
124    * @param jField The JField to add.
125    */
126   public void addField(final JField jField) {
127     if (jField == null) {
128       throw new IllegalArgumentException("argument 'jField' cannot be null");
129     }
130 
131     String name = jField.getName();
132 
133     // -- check for duplicate field name
134     if ((_fields != null) && (_fields.get(name) != null)) {
135       String err = "duplicate name found: " + name;
136       throw new IllegalArgumentException(err);
137     }
138 
139     // -- check for proper modifiers
140     JModifiers modifiers = jField.getModifiers();
141     if (!modifiers.isStatic()) {
142       String err = "Fields added to a JInterface must be static.";
143       throw new IllegalArgumentException(err);
144     }
145     if (modifiers.isPrivate()) {
146       String err = "Fields added to a JInterface must not be private.";
147       throw new IllegalArgumentException(err);
148     }
149 
150     _fields.put(name, jField);
151 
152     // if member is of a type not imported by this class
153     // then add import
154     JType type = jField.getType();
155     while (type.isArray()) {
156       type = ((JArrayType) type).getComponentType();
157     }
158     if (!type.isPrimitive()) {
159       addImport(((JClass) type).getName());
160     }
161 
162     // ensure annotation classes are imported
163     addImport(jField.getAnnotations());
164   }
165 
166   /**
167    * Returns an array of all the JMethodSignatures of this JInterface.
168    *
169    * @return An array of all the JMethodSignatures of this JInterface.
170    */
171   public JMethodSignature[] getMethods() {
172     return _methods.toArray(new JMethodSignature[_methods.size()]);
173   }
174 
175   /**
176    * Returns the JMethodSignature with the given name and occuring at or after the given starting
177    * index.
178    *
179    * @param name The name of the JMethodSignature to return.
180    * @param startIndex The starting index to begin searching from.
181    * @return The JMethodSignature, or null if not found.
182    */
183   public JMethodSignature getMethod(final String name, final int startIndex) {
184     for (JMethodSignature jMethod : _methods) {
185       if (jMethod.getName().equals(name)) {
186         return jMethod;
187       }
188     }
189     return null;
190   }
191 
192   /**
193    * Returns the JMethodSignature at the given index.
194    *
195    * @param index The index of the JMethodSignature to return.
196    * @return The JMethodSignature at the given index.
197    */
198   public JMethodSignature getMethod(final int index) {
199     return _methods.elementAt(index);
200   }
201 
202   /**
203    * Adds the given JMethodSignature to this Jinterface.
204    *
205    * @param jMethodSig The JMethodSignature to add.
206    */
207   public void addMethod(final JMethodSignature jMethodSig) {
208     if (jMethodSig == null) {
209       String err = "The JMethodSignature cannot be null.";
210       throw new IllegalArgumentException(err);
211     }
212 
213     // -- check method name and signatures *add later*
214 
215     // -- keep method list sorted for esthetics when printing
216     // -- START SORT :-)
217     boolean added = false;
218     JModifiers modifiers = jMethodSig.getModifiers();
219     for (int i = 0; i < _methods.size(); i++) {
220       JMethodSignature tmp = _methods.elementAt(i);
221       // -- first compare modifiers
222       if (tmp.getModifiers().isProtected() && !modifiers.isProtected()) {
223         _methods.insertElementAt(jMethodSig, i);
224         added = true;
225         break;
226       }
227       // -- compare names
228       if (jMethodSig.getName().compareTo(tmp.getName()) < 0) {
229         _methods.insertElementAt(jMethodSig, i);
230         added = true;
231         break;
232       }
233     }
234     // -- END SORT
235     if (!added) {
236       _methods.add(jMethodSig);
237     }
238 
239     // -- check parameter packages to make sure we have them
240     // -- in our import list
241 
242     String[] pkgNames = jMethodSig.getParameterClassNames();
243     for (String pkgName : pkgNames) {
244       addImport(pkgName);
245     }
246     // -- check return type to make sure it's included in the
247     // -- import list
248     JType jType = jMethodSig.getReturnType();
249     if (jType != null) {
250       while (jType.isArray()) {
251         jType = ((JArrayType) jType).getComponentType();
252       }
253       if (!jType.isPrimitive()) {
254         addImport(jType.getName());
255       }
256     }
257     // -- check exceptions
258     JClass[] exceptions = jMethodSig.getExceptions();
259     for (JClass exc : exceptions) {
260       addImport(exc.getName());
261     }
262     // -- ensure method and parameter annotations imported
263     addImport(jMethodSig.getAnnotations());
264     JParameter[] params = jMethodSig.getParameters();
265     for (JParameter param : params) {
266       addImport(param.getAnnotations());
267     }
268   }
269 
270   /**
271    * {@inheritDoc}
272    * 
273    * @deprecated Please use the Velocity-template based approach instead.
274    * @see SourceGenerator#setJClassPrinterType(String)
275    */
276   public void print(final JSourceWriter jsw) {
277     print(jsw, false);
278   }
279 
280   /**
281    * Prints the source code for this JInterface to the given JSourceWriter.
282    *
283    * @param jsw The JSourceWriter to print to. Must not be null.
284    * @param classOnly If true, generates the class body without the class header, package
285    *        declaration, or imports.
286    * 
287    * @deprecated Please use the Velocity-template based approach instead.
288    * @see SourceGenerator#setJClassPrinterType(String)
289    */
290   public void print(final JSourceWriter jsw, final boolean classOnly) {
291     if (jsw == null) {
292       throw new IllegalArgumentException("argument 'jsw' should not be null.");
293     }
294 
295     StringBuilder buffer = new StringBuilder(100);
296 
297     if (!classOnly) {
298       printHeader(jsw);
299       printPackageDeclaration(jsw);
300       printImportDeclarations(jsw);
301     }
302 
303     getJDocComment().print(jsw);
304 
305     getAnnotatedElementHelper().printAnnotations(jsw);
306 
307     JModifiers modifiers = getModifiers();
308     if (modifiers.isPrivate()) {
309       buffer.append("private ");
310     } else if (modifiers.isPublic()) {
311       buffer.append("public ");
312     }
313 
314     if (modifiers.isAbstract()) {
315       buffer.append("abstract ");
316     }
317 
318     buffer.append("interface ").append(getLocalName()).append(' ');
319     if (getInterfaceCount() > 0) {
320       Enumeration<String> enumeration = getInterfaces();
321       boolean endl = false;
322       if (getInterfaceCount() > 1) {
323         jsw.writeln(buffer.toString());
324         buffer.setLength(0);
325         endl = true;
326       }
327       buffer.append("extends ");
328       while (enumeration.hasMoreElements()) {
329         buffer.append(enumeration.nextElement());
330         if (enumeration.hasMoreElements()) {
331           buffer.append(", ");
332         }
333       }
334       if (endl) {
335         jsw.writeln(buffer.toString());
336         buffer.setLength(0);
337       } else {
338         buffer.append(' ');
339       }
340     }
341 
342     buffer.append('{');
343     jsw.writeln(buffer.toString());
344     buffer.setLength(0);
345     jsw.writeln();
346 
347     jsw.indent();
348 
349     // -- declare static members
350 
351     if (!_fields.isEmpty()) {
352       jsw.writeln();
353       jsw.writeln("  //--------------------------/");
354       jsw.writeln(" //- Class/Member Variables -/");
355       jsw.writeln("//--------------------------/");
356       jsw.writeln();
357     }
358 
359     for (JField jField : _fields.values()) {
360 
361       // -- print Java comment
362       JDocComment comment = jField.getComment();
363       if (comment != null) {
364         comment.print(jsw);
365       }
366 
367       // -- annotations
368       jField.printAnnotations(jsw);
369 
370       // -- print member
371       jsw.write(jField.getModifiers().toString());
372       jsw.write(' ');
373 
374       JType type = jField.getType();
375       String typeName = type.toString();
376       // -- for esthetics use short name in some cases
377       if (typeName.equals(toString())) {
378         typeName = type.getLocalName();
379       }
380       jsw.write(typeName);
381       jsw.write(' ');
382       jsw.write(jField.getName());
383 
384       String init = jField.getInitString();
385       if (init != null) {
386         jsw.write(" = ");
387         jsw.write(init);
388       }
389 
390       jsw.writeln(';');
391       jsw.writeln();
392     }
393 
394     // -- print method signatures
395 
396     if (!_methods.isEmpty()) {
397       jsw.writeln();
398       jsw.writeln("  //-----------/");
399       jsw.writeln(" //- Methods -/");
400       jsw.writeln("//-----------/");
401       jsw.writeln();
402     }
403 
404     for (JMethodSignature signature : _methods) {
405       signature.print(jsw);
406       jsw.writeln(';');
407     }
408 
409     jsw.unindent();
410     jsw.writeln('}');
411     jsw.flush();
412     jsw.close();
413   }
414 
415 }