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 }