001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 2001-2002 (C) Intalio, Inc. All Rights Reserved.
042: */package org.exolab.javasource;
043:
044: import java.util.Enumeration;
045: import java.util.Vector;
046:
047: /**
048: * A representation of the Java Source code for a Java Interface. This is a
049: * useful utility when creating in memory source code. The code in this package
050: * was modelled after the Java Reflection API as much as possible to reduce the
051: * learning curve.
052: *
053: * @author <a href="mailto:skopp AT riege DOT de">Martin Skopp</a>
054: * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
055: * @version $Revision: 6673 $ $Date: 2005-02-26 17:30:28 -0700 (Sat, 26 Feb 2005) $
056: */
057: public final class JInterface extends JStructure {
058: //--------------------------------------------------------------------------
059:
060: /** Default size of the map for fields. */
061: private static final int DEFAULT_FIELD_MAP_SIZE = 3;
062:
063: //--------------------------------------------------------------------------
064:
065: /** The fields for this JInterface. */
066: private JNamedMap _fields;
067:
068: /** The list of methods of this JInterface. */
069: private Vector _methods;
070:
071: //--------------------------------------------------------------------------
072:
073: /**
074: * Creates a new JInterface with the given name.
075: *
076: * @param name The name of the JInterface.
077: */
078: public JInterface(final String name) {
079: super (name);
080:
081: _fields = null;
082: _methods = new Vector();
083:
084: //-- initialize default Java doc
085: getJDocComment().appendComment(
086: "Interface " + getLocalName() + ".");
087: }
088:
089: //--------------------------------------------------------------------------
090:
091: /**
092: * {@inheritDoc}
093: */
094: public void addImport(final String className) {
095: if (className == null || className.length() == 0) {
096: return;
097: }
098: addImportInternal(className);
099: }
100:
101: /**
102: * Adds the given JMember to this Jinterface.
103: * <p>
104: * This method is implemented by subclasses and should only accept the
105: * proper types for the subclass otherwise an IllegalArgumentException will
106: * be thrown.
107: *
108: * @param jMember The JMember to add to this JStructure.
109: */
110: public void addMember(final JMember jMember) {
111: if (jMember == null) {
112: throw new IllegalArgumentException(
113: "argument 'jMember' may not be null.");
114: }
115: if (jMember instanceof JField) {
116: addField((JField) jMember);
117: } else {
118: throw new IllegalArgumentException(
119: "invalid member for JInterface: "
120: + jMember.toString());
121: }
122: }
123:
124: /**
125: * Returns an array of all the JFields of this Jinterface.
126: *
127: * @return An array of all the JFields of this Jinterface.
128: */
129: public JField[] getFields() {
130: if (_fields == null) {
131: return new JField[0];
132: }
133: int size = _fields.size();
134: JField[] farray = new JField[size];
135: for (int i = 0; i < size; i++) {
136: farray[i] = (JField) _fields.get(i);
137: }
138: return farray;
139: }
140:
141: /**
142: * Returns the field with the given name, or null if no field was found with
143: * the given name.
144: *
145: * @param name The name of the field to return.
146: * @return The field with the given name, or null if no field was found with
147: * the given name.
148: */
149: public JField getField(final String name) {
150: if (_fields == null) {
151: return null;
152: }
153: return (JField) _fields.get(name);
154: }
155:
156: /**
157: * Adds the given JField to this Jinterface.
158: * <p>
159: * This method is implemented by subclasses and should only accept the
160: * proper fields for the subclass otherwise an IllegalArgumentException will
161: * be thrown. For example a JInterface will only accept static fields.
162: *
163: * @param jField The JField to add.
164: */
165: public void addField(final JField jField) {
166: if (jField == null) {
167: throw new IllegalArgumentException(
168: "argument 'jField' cannot be null");
169: }
170:
171: String name = jField.getName();
172:
173: //-- check for duplicate field name
174: if ((_fields != null) && (_fields.get(name) != null)) {
175: String err = "duplicate name found: " + name;
176: throw new IllegalArgumentException(err);
177: }
178:
179: //-- check for proper modifiers
180: JModifiers modifiers = jField.getModifiers();
181: if (!modifiers.isStatic()) {
182: String err = "Fields added to a JInterface must be static.";
183: throw new IllegalArgumentException(err);
184: }
185: if (modifiers.isPrivate()) {
186: String err = "Fields added to a JInterface must not be private.";
187: throw new IllegalArgumentException(err);
188: }
189:
190: //-- only initialize fields if we need it, many interfaces
191: //-- don't contain any fields, no need to waste space
192: if (_fields == null) {
193: _fields = new JNamedMap(DEFAULT_FIELD_MAP_SIZE);
194: }
195:
196: _fields.put(name, jField);
197:
198: // if member is of a type not imported by this class
199: // then add import
200: JType type = jField.getType();
201: while (type.isArray()) {
202: type = ((JArrayType) type).getComponentType();
203: }
204: if (!type.isPrimitive()) {
205: addImport(((JClass) type).getName());
206: }
207:
208: // ensure annotation classes are imported
209: addImport(jField.getAnnotations());
210: }
211:
212: /**
213: * Returns an array of all the JMethodSignatures of this JInterface.
214: *
215: * @return An array of all the JMethodSignatures of this JInterface.
216: */
217: public JMethodSignature[] getMethods() {
218: JMethodSignature[] marray = new JMethodSignature[_methods
219: .size()];
220: _methods.copyInto(marray);
221: return marray;
222: }
223:
224: /**
225: * Returns the JMethodSignature with the given name and occuring at or
226: * after the given starting index.
227: *
228: * @param name The name of the JMethodSignature to return.
229: * @param startIndex The starting index to begin searching from.
230: * @return The JMethodSignature, or null if not found.
231: */
232: public JMethodSignature getMethod(final String name,
233: final int startIndex) {
234: for (int i = startIndex; i < _methods.size(); i++) {
235: JMethodSignature jMethod = (JMethodSignature) _methods
236: .elementAt(i);
237: if (jMethod.getName().equals(name)) {
238: return jMethod;
239: }
240: }
241: return null;
242: }
243:
244: /**
245: * Returns the JMethodSignature at the given index.
246: *
247: * @param index The index of the JMethodSignature to return.
248: * @return The JMethodSignature at the given index.
249: */
250: public JMethodSignature getMethod(final int index) {
251: return (JMethodSignature) _methods.elementAt(index);
252: }
253:
254: /**
255: * Adds the given JMethodSignature to this Jinterface.
256: *
257: * @param jMethodSig The JMethodSignature to add.
258: */
259: public void addMethod(final JMethodSignature jMethodSig) {
260: if (jMethodSig == null) {
261: String err = "The JMethodSignature cannot be null.";
262: throw new IllegalArgumentException(err);
263: }
264:
265: //-- check method name and signatures *add later*
266:
267: //-- keep method list sorted for esthetics when printing
268: //-- START SORT :-)
269: boolean added = false;
270: JModifiers modifiers = jMethodSig.getModifiers();
271: for (int i = 0; i < _methods.size(); i++) {
272: JMethodSignature tmp = (JMethodSignature) _methods
273: .elementAt(i);
274: //-- first compare modifiers
275: if (tmp.getModifiers().isProtected()
276: && !modifiers.isProtected()) {
277: _methods.insertElementAt(jMethodSig, i);
278: added = true;
279: break;
280: }
281: //-- compare names
282: if (jMethodSig.getName().compareTo(tmp.getName()) < 0) {
283: _methods.insertElementAt(jMethodSig, i);
284: added = true;
285: break;
286: }
287: }
288: //-- END SORT
289: if (!added) {
290: _methods.addElement(jMethodSig);
291: }
292:
293: //-- check parameter packages to make sure we have them
294: //-- in our import list
295:
296: String[] pkgNames = jMethodSig.getParameterClassNames();
297: for (int i = 0; i < pkgNames.length; i++) {
298: addImport(pkgNames[i]);
299: }
300: //-- check return type to make sure it's included in the
301: //-- import list
302: JType jType = jMethodSig.getReturnType();
303: if (jType != null) {
304: while (jType.isArray()) {
305: jType = ((JArrayType) jType).getComponentType();
306: }
307: if (!jType.isPrimitive()) {
308: addImport(jType.getName());
309: }
310: }
311: //-- check exceptions
312: JClass[] exceptions = jMethodSig.getExceptions();
313: for (int i = 0; i < exceptions.length; i++) {
314: addImport(exceptions[i].getName());
315: }
316: //-- ensure method and parameter annotations imported
317: addImport(jMethodSig.getAnnotations());
318: JParameter[] params = jMethodSig.getParameters();
319: for (int i = 0; i < params.length; i++) {
320: addImport(params[i].getAnnotations());
321: }
322: }
323:
324: //--------------------------------------------------------------------------
325:
326: /**
327: * {@inheritDoc}
328: */
329: public void print(final JSourceWriter jsw) {
330: print(jsw, false);
331: }
332:
333: /**
334: * Prints the source code for this JInterface to the given JSourceWriter.
335: *
336: * @param jsw The JSourceWriter to print to. Must not be null.
337: * @param classOnly If true, generates the class body without the class
338: * header, package declaration, or imports.
339: */
340: public void print(final JSourceWriter jsw, final boolean classOnly) {
341: if (jsw == null) {
342: throw new IllegalArgumentException(
343: "argument 'jsw' should not be null.");
344: }
345:
346: StringBuffer buffer = new StringBuffer();
347:
348: if (!classOnly) {
349: printHeader(jsw);
350: printPackageDeclaration(jsw);
351: printImportDeclarations(jsw);
352: }
353:
354: getJDocComment().print(jsw);
355:
356: getAnnotatedElementHelper().printAnnotations(jsw);
357:
358: buffer.setLength(0);
359:
360: JModifiers modifiers = getModifiers();
361: if (modifiers.isPrivate()) {
362: buffer.append("private ");
363: } else if (modifiers.isPublic()) {
364: buffer.append("public ");
365: }
366:
367: if (modifiers.isAbstract()) {
368: buffer.append("abstract ");
369: }
370:
371: buffer.append("interface ");
372: buffer.append(getLocalName());
373: buffer.append(' ');
374: if (getInterfaceCount() > 0) {
375: Enumeration enumeration = getInterfaces();
376: boolean endl = false;
377: if (getInterfaceCount() > 1) {
378: jsw.writeln(buffer.toString());
379: buffer.setLength(0);
380: endl = true;
381: }
382: buffer.append("extends ");
383: while (enumeration.hasMoreElements()) {
384: buffer.append(enumeration.nextElement());
385: if (enumeration.hasMoreElements()) {
386: buffer.append(", ");
387: }
388: }
389: if (endl) {
390: jsw.writeln(buffer.toString());
391: buffer.setLength(0);
392: } else {
393: buffer.append(' ');
394: }
395: }
396:
397: buffer.append('{');
398: jsw.writeln(buffer.toString());
399: buffer.setLength(0);
400: jsw.writeln();
401:
402: jsw.indent();
403:
404: //-- declare static members
405:
406: if (_fields != null) {
407: if (_fields.size() > 0) {
408: jsw.writeln();
409: jsw.writeln(" //--------------------------/");
410: jsw.writeln(" //- Class/Member Variables -/");
411: jsw.writeln("//--------------------------/");
412: jsw.writeln();
413: }
414:
415: for (int i = 0; i < _fields.size(); i++) {
416:
417: JField jField = (JField) _fields.get(i);
418:
419: //-- print Java comment
420: JDocComment comment = jField.getComment();
421: if (comment != null) {
422: comment.print(jsw);
423: }
424:
425: // -- annotations
426: jField.printAnnotations(jsw);
427:
428: // -- print member
429: jsw.write(jField.getModifiers().toString());
430: jsw.write(' ');
431:
432: JType type = jField.getType();
433: String typeName = type.toString();
434: //-- for esthetics use short name in some cases
435: if (typeName.equals(toString())) {
436: typeName = type.getLocalName();
437: }
438: jsw.write(typeName);
439: jsw.write(' ');
440: jsw.write(jField.getName());
441:
442: String init = jField.getInitString();
443: if (init != null) {
444: jsw.write(" = ");
445: jsw.write(init);
446: }
447:
448: jsw.writeln(';');
449: jsw.writeln();
450: }
451: }
452:
453: //-- print method signatures
454:
455: if (_methods.size() > 0) {
456: jsw.writeln();
457: jsw.writeln(" //-----------/");
458: jsw.writeln(" //- Methods -/");
459: jsw.writeln("//-----------/");
460: jsw.writeln();
461: }
462:
463: for (int i = 0; i < _methods.size(); i++) {
464: JMethodSignature signature = (JMethodSignature) _methods
465: .elementAt(i);
466: signature.print(jsw);
467: jsw.writeln(';');
468: }
469:
470: jsw.unindent();
471: jsw.writeln('}');
472: jsw.flush();
473: jsw.close();
474: }
475:
476: //--------------------------------------------------------------------------
477: }
|