001: package Schmortopf.FileStructure.Descriptions;
002:
003: /**
004: * Holds information for a Constructor object.
005: * Constructors can deal with field classes
006: * as well as token tree nodes.
007: */
008:
009: import javax.swing.tree.*;
010: import java.lang.reflect.*;
011: import java.util.*;
012: import Schmortopf.Utility.Vectorizable;
013: import Schmortopf.Utility.SchmortopfConstants;
014: import Schmortopf.Utility.BooleanInteger;
015: import Schmortopf.Utility.StringUtilities;
016:
017: public class FileStructureDescriptionForField implements Vectorizable,
018: StringComparable {
019:
020: // Caution: Update the Vectorizable methods **AND** the cloneInstance() method,
021: // when this datastructure changes.
022:
023: public int modifiers = 0; // coded like in java.lang.reflect.Modifier
024: public boolean isPrimitiveType = false;
025: public BooleanInteger isArrayType = new BooleanInteger(false, 0);
026: public String packageName = "";
027: public StringWithPosition simpleClassName = new StringWithPosition();
028: public StringWithPosition objectNameWithPosition = new StringWithPosition();
029:
030: // Scope indices : Important for local attributes, which are hold
031: // in the localBlockFieldDescriptions Vector of the FSD.
032: public int scopeStartLine = 0;
033: public int scopeEndLine = 0;
034: // for member attributes, scopeStartLine and scopeEndLine
035: // will not be set and are both zero therefore.
036:
037: public GenericTypeRestrictionDescription[] genericRestrictions = new GenericTypeRestrictionDescription[0];
038:
039: // Caution: Update the Vectorizable methods **AND** the cloneInstance() method,
040: // when this datastructure changes.
041:
042: /**
043: * Class file based constructor
044: */
045: public FileStructureDescriptionForField(final Field field) {
046: // We just have the same coding like reflection for the modifiers :
047: this .modifiers = field.getModifiers();
048: this .isPrimitiveType = field.getType().isPrimitive();
049:
050: // Array or not :
051: boolean is_Array = false;
052: int array_Dimension = 0;
053: Class this Type = field.getType();
054: if (this Type != null) {
055: // Find out the dimension [ see getTypeName in reflect.Field.java - done like there ]
056: if (this Type != null) {
057: is_Array = this Type.isArray();
058: while (this Type.isArray()) {
059: array_Dimension++;
060: this Type = this Type.getComponentType();
061: if (this Type == null)
062: break;
063: }
064: }
065: }
066: // done, so assign that attribute :
067: this .isArrayType = new BooleanInteger(is_Array, array_Dimension);
068: this .packageName = "";
069: if (field.getType() != null) {
070: if (field.getType().getPackage() != null) {
071: this .packageName = field.getType().getPackage()
072: .getName();
073: }
074: }
075: // We must use getTypeName(), which translates array types correctly:
076: this .simpleClassName.content = this .getLastIdentifier(this
077: .getTypeName(field.getType()));
078: this .objectNameWithPosition.content = field.getName();
079: } // Constructor
080:
081: /**
082: * Java file based constructor - values are filled in by caller,
083: * cause utilities are there.
084: */
085: public FileStructureDescriptionForField() {
086: } // Constructor
087:
088: /**
089: * Constructor containing all member attributes to be set,
090: * used for explicit constructions, can be used by the umlManager f.ex.
091: *
092: * Parameters: See explanations on top of this class.
093: * modifiers: coded like in java.lang.reflect.Modifier
094: * All arrays must exist (set zero length at least)
095: */
096: public FileStructureDescriptionForField(final int modifiers,
097: final boolean isPrimitiveType,
098: final BooleanInteger isArrayType, String packageName,
099: String simple_ClassName, String attributeName) {
100: this .modifiers = modifiers;
101: this .isPrimitiveType = isPrimitiveType;
102: this .isArrayType = isArrayType;
103: this .packageName = packageName;
104: this .simpleClassName = new StringWithPosition(simple_ClassName,
105: 0, 0, 0, 0); // linenumber later adjusted
106: this .objectNameWithPosition = new StringWithPosition(
107: attributeName, 0, 0, 0, 0); // linenumber later adjusted
108: } // Constructor
109:
110: /**
111: * Returns a cloned instance of this one.
112: * Caution: This must be updated, when attributes of this class are added or removed.
113: * Reason for this: No constructor with all attributes exists, because the numbers
114: * for StringWithPositions are inserted later after construction by the parser normally.
115: */
116: public FileStructureDescriptionForField cloneInstance() {
117: FileStructureDescriptionForField c = new FileStructureDescriptionForField();
118: c.modifiers = this .modifiers;
119: c.isPrimitiveType = this .isPrimitiveType;
120: c.isArrayType = this .isArrayType;
121: c.packageName = this .packageName;
122: c.simpleClassName = this .simpleClassName.cloneInstance();
123: c.objectNameWithPosition = this .objectNameWithPosition
124: .cloneInstance();
125: c.scopeStartLine = this .scopeStartLine;
126: c.scopeEndLine = this .scopeEndLine;
127: return c;
128: }
129:
130: public boolean isPublic() {
131: return this .isModifierKey("public");
132: }
133:
134: public boolean isPrivate() {
135: return this .isModifierKey("private");
136: }
137:
138: public boolean isProtected() {
139: return this .isModifierKey("protected");
140: }
141:
142: public boolean isStatic() {
143: return this .isModifierKey("static");
144: }
145:
146: public boolean isPackageScope() {
147: return (!this .isModifierKey("public")
148: && !this .isModifierKey("private") && !this
149: .isModifierKey("protected"));
150: }
151:
152: private String getTypeName(Class type) {
153: if (type.isArray()) {
154: try {
155: Class cl = type;
156: int dimensions = 0;
157: while (cl.isArray()) {
158: dimensions++;
159: cl = cl.getComponentType();
160: }
161: StringBuffer sb = new StringBuffer();
162: sb.append(cl.getName());
163: for (int i = 0; i < dimensions; i++) {
164: sb.append("[]");
165: }
166: return sb.toString();
167: } catch (Throwable e) {
168: /*FALLTHRU*/
169: }
170: }
171: return type.getName();
172: }
173:
174: /**
175: * Returns the last token in a string delimited by points.
176: */
177: private String getLastIdentifier(String fullyQualifiedName) {
178: String[] tokens = StringUtilities.SplitString(
179: fullyQualifiedName, ".");
180: return tokens[tokens.length - 1]; // The last one
181: }
182:
183: private boolean isModifierKey(final String searchKey) {
184: boolean keyFound = false;
185: String[] tokens = StringUtilities.SplitString(Modifier
186: .toString(this .modifiers), " ");
187: for (int i = 0; i < tokens.length; i++) {
188: if (tokens[i].equals(searchKey)) {
189: keyFound = true;
190: break;
191: }
192: }
193: return keyFound;
194: } // isModifierKey
195:
196: /**
197: * Full version
198: */
199: public String getTextDescription() {
200: final StringBuffer buf = new StringBuffer();
201: buf.append(Modifier.toString(this .modifiers) + " ");
202: buf.append(this .packageName + " ");
203: buf.append(this .simpleClassName.content);
204: if (this .isArrayType.booleanValue) {
205: for (int i = 0; i < this .isArrayType.intValue; i++)
206: buf.append(SchmortopfConstants.ArraySymbol);
207: }
208: buf.append(" ");
209: buf.append(this .objectNameWithPosition.content);
210:
211: // add to scope:
212: buf.append(" scopeStartLine= " + this .scopeStartLine);
213: buf.append(" scopeEndLine= " + this .scopeEndLine);
214:
215: return buf.toString().trim();
216: } // getTextDescription
217:
218: /**
219: * Description optional filtered visibility modifiers (public,private,protected)
220: *
221: * Used for the name of method leafs in the fileComponentsTree
222: * and the CodeCompletion menu.
223: */
224: public String getShortTextDescription(
225: final boolean doFilterVisibility) {
226: final StringBuffer buf = new StringBuffer();
227: buf.append(this .objectNameWithPosition.content + " ");
228: buf.append(this .packageName + " ");
229: buf.append(this .simpleClassName.content);
230: // append generic restrictions, if there are some:
231: if (this .genericRestrictions.length > 0) {
232: buf.append("<");
233: for (int i = 0; i < this .genericRestrictions.length; i++) {
234: buf.append(this .genericRestrictions[i]
235: .getShortTextDescription());
236: if (i < this .genericRestrictions.length - 1)
237: buf.append(",");
238: }
239: buf.append(">");
240: } // if
241: // append array brackets if required:
242: if (this .isArrayType.booleanValue) {
243: for (int i = 0; i < this .isArrayType.intValue; i++)
244: buf.append(SchmortopfConstants.ArraySymbol);
245: }
246: buf.append(" ");
247:
248: String[] tokens = StringUtilities.SplitString(Modifier
249: .toString(this .modifiers), " ");
250: int numberOfTokens = tokens.length;
251: if (doFilterVisibility) {
252: StringBuffer filteredModifiers = new StringBuffer();
253: for (int i = 0; i < numberOfTokens; i++) {
254: if (!(tokens[i].equals("public"))
255: && !(tokens[i].equals("private"))
256: && !(tokens[i].equals("protected"))) {
257: filteredModifiers.append(tokens[i] + " ");
258: }
259: }
260: if (filteredModifiers.length() > 0) {
261: buf.append(" is ");
262: buf.append(filteredModifiers);
263: }
264: } else {
265: if (numberOfTokens > 0) {
266: buf.append(" is ");
267: }
268: buf.append(Modifier.toString(this .modifiers) + " ");
269: }
270: return buf.toString().trim();
271: } // getTextDescription
272:
273: public String getJavaSourceCompatibleTextDescription() {
274: StringBuffer buf = new StringBuffer();
275: buf.append(Modifier.toString(this .modifiers) + " ");
276: buf.append(this .simpleClassName.content);
277: // append generic restrictions, if there are some:
278: if (this .genericRestrictions.length > 0) {
279: buf.append("<");
280: for (int i = 0; i < this .genericRestrictions.length; i++) {
281: buf.append(this .genericRestrictions[i]
282: .getJavaSourceCompatibleTextDescription());
283: if (i < this .genericRestrictions.length - 1)
284: buf.append(",");
285: }
286: buf.append(">");
287: } // if
288: // Append array brackets if required:
289: if (this .isArrayType.booleanValue) {
290: for (int i = 0; i < this .isArrayType.intValue; i++)
291: buf.append(SchmortopfConstants.ArraySymbol);
292: }
293: buf.append(" " + this .objectNameWithPosition.content + ";");
294: return buf.toString().trim();
295: } // getJavaSourceCompatibleTextDescription
296:
297: /**
298: * Debug version
299: */
300: public String getDebugTextDescription() {
301: final StringBuffer buf = new StringBuffer();
302: buf.append("Modifier=" + Modifier.toString(this .modifiers)
303: + " package=");
304: buf.append(this .packageName + " classname=");
305: buf.append(this .simpleClassName.content);
306: if (this .isArrayType.booleanValue) {
307: for (int i = 0; i < this .isArrayType.intValue; i++)
308: buf.append(SchmortopfConstants.ArraySymbol);
309: }
310: // append generic restrictions, if there are some:
311: if (this .genericRestrictions.length > 0) {
312: buf.append("<");
313: for (int i = 0; i < this .genericRestrictions.length; i++) {
314: buf.append(this .genericRestrictions[i]
315: .getJavaSourceCompatibleTextDescription());
316: if (i < this .genericRestrictions.length - 1)
317: buf.append(",");
318: }
319: buf.append(">");
320: } // if
321: buf.append(" objectname=");
322: buf.append(this .objectNameWithPosition.content
323: + " scopestart=");
324: buf.append(this .scopeStartLine + " scopeend=");
325: buf.append(this .scopeEndLine);
326: return buf.toString().trim();
327: } // getTextDescription
328:
329: /**
330: * Implementation of the Vectorizable interface.
331: * Returns the VectorRepresentation of the object's datacontent
332: */
333: public Vector getVectorRepresentation() throws Exception {
334: final Vector rep = new Vector();
335: rep.addElement(new Integer(this .modifiers));
336: rep.addElement(new Boolean(this .isPrimitiveType));
337: rep.addElement(this .isArrayType.getVectorRepresentation());
338: rep.addElement(this .packageName);
339: rep.addElement(simpleClassName.getVectorRepresentation());
340: rep.addElement(this .objectNameWithPosition
341: .getVectorRepresentation());
342: rep.addElement(new Integer(this .scopeStartLine));
343: rep.addElement(new Integer(this .scopeEndLine));
344: rep.addElement(new Integer(this .genericRestrictions.length));
345: for (int i = 0; i < this .genericRestrictions.length; i++) {
346: rep.addElement(this .genericRestrictions[i]
347: .getVectorRepresentation());
348: }
349: return rep;
350: } // getVectorRepresentation
351:
352: /**
353: * Implementation of the Vectorizable interface.
354: * Sets the object's content to the passed vectorRepresentation.
355: */
356: public void createFromVectorRepresentation(final Vector rep) {
357: int repCounter = 0;
358: this .modifiers = ((Integer) rep.elementAt(repCounter++))
359: .intValue();
360: this .isPrimitiveType = ((Boolean) rep.elementAt(repCounter++))
361: .booleanValue();
362:
363: Vector arrayTypeRepresentation = (Vector) rep
364: .elementAt(repCounter++);
365: this .isArrayType = new BooleanInteger(arrayTypeRepresentation);
366:
367: this .packageName = (String) rep.elementAt(repCounter++);
368: this .simpleClassName = new StringWithPosition();
369: final Vector simpleClassNameRep = (Vector) rep
370: .elementAt(repCounter++);
371: this .simpleClassName
372: .createFromVectorRepresentation(simpleClassNameRep);
373:
374: this .objectNameWithPosition = new StringWithPosition();
375: final Vector objectNameRep = (Vector) rep
376: .elementAt(repCounter++);
377: this .objectNameWithPosition
378: .createFromVectorRepresentation(objectNameRep);
379:
380: this .scopeStartLine = ((Integer) rep.elementAt(repCounter++))
381: .intValue();
382: this .scopeEndLine = ((Integer) rep.elementAt(repCounter++))
383: .intValue();
384:
385: int numberOfGenericRestrictions = ((Integer) rep
386: .elementAt(repCounter++)).intValue();
387: this .genericRestrictions = new GenericTypeRestrictionDescription[numberOfGenericRestrictions];
388: for (int i = 0; i < numberOfGenericRestrictions; i++) {
389: final Vector this GenericRep = (Vector) rep
390: .elementAt(repCounter++);
391: this .genericRestrictions[i] = new GenericTypeRestrictionDescription();
392: this .genericRestrictions[i]
393: .createFromVectorRepresentation(this GenericRep);
394: }
395:
396: } // createFromVectorRepresentation
397:
398: /**
399: * Implementation of the StringComparable interface.
400: * Used by a comparator for sorting alphabetically.
401: */
402: public String getComparatorString() {
403: if (this .objectNameWithPosition != null) {
404: return this .objectNameWithPosition.content;
405: } else {
406: return "";
407: }
408: } // getComparatorValue
409:
410: /**
411: * Returns the classname as entered in the source code.
412: * Meaning: If the source code class name is java.awt.Color,
413: * this returns java.awt.Color.
414: * But if the classname is entered as simple name (like Color)
415: * this method simply will return "Color" and one has to
416: * combine it with all import statements for finding out
417: * the valid fully qualified class name.
418: *
419: * Note: For getting the FSD of this field, use the
420: * FileStructureDescriptionManager method getFSDForField()
421: * which uses the import statements of the class containing
422: * this field.
423: * @param useArrayTypeSymbolForArrays: If this is set, array type symbols "[ ][ ]..." will
424: * be appended to the returned name. If this is not set, the caller must
425: * examine this.isArrayType itself for finding out, if its an array or a single value.
426: */
427: public String getFullyQualifiedClassName(
428: boolean useArrayTypeSymbolForArrays) {
429: if (this .packageName.length() > 0) {
430: String fqname = null;
431: if (this .isArrayType.booleanValue) {
432: fqname = this .packageName + "."
433: + this .simpleClassName.content;
434: if (useArrayTypeSymbolForArrays) {
435: for (int i = 0; i < this .isArrayType.intValue; i++) {
436: fqname += SchmortopfConstants.ArraySymbol;
437: }
438: }
439: } else {
440: fqname = this .packageName + "."
441: + this .simpleClassName.content;
442: }
443: return fqname;
444: } else {
445: String fqname = null;
446: if (this .isArrayType.booleanValue) {
447: fqname = this .simpleClassName.content;
448: if (useArrayTypeSymbolForArrays) {
449: for (int i = 0; i < this .isArrayType.intValue; i++) {
450: fqname += SchmortopfConstants.ArraySymbol;
451: }
452: }
453: } else {
454: fqname = this .simpleClassName.content;
455: }
456: return fqname;
457: }
458: }
459:
460: /**
461: * GC assistance
462: */
463: public void clearAttributes() {
464: this .isArrayType = null;
465: this .packageName = null;
466: if (this .simpleClassName != null) {
467: this .simpleClassName.content = null;
468: this .simpleClassName = null;
469: }
470: this .objectNameWithPosition = null;
471: }
472:
473: } // FileStructureDescriptionForField
|