001: /*
002: * Project: BeautyJ - Customizable Java Source Code Transformer
003: * Class: de.gulden.util.javasource.Package
004: * Version: 1.1
005: *
006: * Date: 2004-09-29
007: *
008: * Note: Contains auto-generated Javadoc comments created by BeautyJ.
009: *
010: * This is licensed under the GNU General Public License (GPL)
011: * and comes with NO WARRANTY. See file license.txt for details.
012: *
013: * Author: Jens Gulden
014: * Email: beautyj@jensgulden.de
015: */
016:
017: package de.gulden.util.javasource;
018:
019: import de.gulden.util.xml.XMLToolbox;
020: import de.gulden.util.javasource.jjt.Node;
021: import javax.xml.parsers.*;
022: import org.w3c.dom.*;
023: import java.io.*;
024: import java.util.*;
025:
026: /**
027: * Represents a Java package.
028: *
029: * @author Jens Gulden
030: * @version 1.1
031: */
032: public class Package extends SourceObject implements PackageMember {
033:
034: // ------------------------------------------------------------------------
035: // --- fields ---
036: // ------------------------------------------------------------------------
037:
038: /**
039: * The my class.
040: */
041: public Vector myClass;
042:
043: /**
044: * The children.
045: */
046: public Vector children;
047:
048: /**
049: * The father.
050: */
051: public Package father;
052:
053: // ------------------------------------------------------------------------
054: // --- constructor ---
055: // ------------------------------------------------------------------------
056:
057: /**
058: * Creates a new instance of Package.
059: */
060: public Package() {
061: myClass = new Vector();
062: children = new Vector();
063: name = ""; // initially treat as default (base-)package
064: }
065:
066: // ------------------------------------------------------------------------
067: // --- methods ---
068: // ------------------------------------------------------------------------
069:
070: /**
071: * Sets the name.
072: */
073: public void setName(String qualifiedName) {
074: super .setName(qualifiedName);
075: initEmptyFathers(); // !!
076: }
077:
078: public void add(PackageMember p) {
079: p.addToPackage(this );
080: }
081:
082: /**
083: * Returns a Class object that carries the qualifiedName, if the class
084: * is contained in this package, or if it is contained in any sub-package
085: * of this package, or is an inner class of any class inside this package.
086: *
087: * @return The Class representation, or <code>null</code> if not found.
088: */
089: public Class findClass(String qualifiedName) {
090: String selfName = this .getName();
091: boolean base = (selfName.equals(""));
092: String q;
093: if (!base) {
094: if (qualifiedName.startsWith(selfName + ".")) {
095: q = qualifiedName.substring(selfName.length() + 1);
096: } else {
097: return null;
098: }
099: } else {
100: q = qualifiedName;
101: }
102: // q now is stripped by self name (like 'de.gulden.application.beautyj.BeautyJ' 'application.beautyj.BeautyJ' if this is 'de.gulden')
103: String firstPart;
104: int dot = q.indexOf('.');
105: if (dot != -1) {
106: firstPart = q.substring(0, dot);
107: String find;
108: if (!base) {
109: find = selfName + "." + firstPart;
110: } else {
111: find = firstPart;
112: }
113: // find could be a subpackage of this, or an outer class if qualifiedName is an inner class
114: // inner package?
115: NamedIterator it = getInnerPackages();
116: Package p = (Package) it.find(find);
117: if (p != null) {
118: return p.findClass(qualifiedName); // recursion
119: }
120: // must be looking for an inner class of a class in this package now
121: it = getClasses();
122: Class c = (Class) it.find(find);
123: if (c != null) {
124: ClassInner ci = c.findInnerClass(qualifiedName);
125: return ci;
126: } else {
127: return null;
128: }
129: } else {
130: // can only be a class in this package
131: NamedIterator it = getClasses();
132: Class c = (Class) it.find(qualifiedName);
133: return c;
134: }
135: }
136:
137: /**
138: * Returns a Package object that carries the qualifiedName, if the package
139: * is this package, or if it is contained in this or any sub-package
140: * of this package.
141: *
142: * @return The Package representation, or <code>null</code> if not found.
143: */
144: public Package findPackage(String qualifiedName) {
145: String selfName = this .getName();
146: boolean base = (selfName.equals(""));
147: if (selfName.equals(qualifiedName)) {
148: return this ;
149: }
150: String q;
151: if (!base) {
152: if (qualifiedName.startsWith(selfName + ".")) {
153: q = qualifiedName.substring(selfName.length() + 1);
154: } else {
155: return null;
156: }
157: } else {
158: q = qualifiedName;
159: }
160: // q now is stripped by self name (like 'de.gulden.application.beautyj' 'application.beautyj' if this is 'de.gulden')
161: String find;
162: String firstPart;
163: int dot = q.indexOf('.');
164: if (dot != -1) {
165: firstPart = q.substring(0, dot);
166: if (!base) {
167: find = selfName + "." + firstPart;
168: } else {
169: find = firstPart;
170: }
171: // find can only be a subpackage of this, otherwise not found
172: } else {
173: // can only be a sub-package of this package
174: find = qualifiedName;
175: }
176: NamedIterator it = getInnerPackages();
177: Package p = (Package) it.find(find);
178: if ((p != null) && (find != qualifiedName)) { // wasn't the final package to find
179: p = p.findPackage(qualifiedName); // recursion
180: }
181: return p;
182: }
183:
184: /**
185: * Returns an iterator that carries all classes and interfaces in this package.
186: */
187: public NamedIterator getClasses() {
188: NamedIterator it = new NamedIterator(myClass);
189: return it;
190: }
191:
192: /**
193: * Returns an iterator that carries all classes and interfaces in this package
194: * and recursively in all its sub-packages.
195: */
196: public NamedIterator getAllClasses() {
197: Vector v = new Vector();
198: for (NamedIterator it = getClasses(); it.hasMore();) {
199: v.addElement(it.next());
200: }
201: for (NamedIterator it = getInnerPackages(); it.hasMore();) {
202: Package p = (Package) it.next();
203: for (NamedIterator it2 = p.getAllClasses(); it2.hasMore();) {
204: v.addElement(it2.next());
205: }
206: }
207: return new NamedIterator(v);
208: }
209:
210: /**
211: * Returns an iterator that carries all direct sub-packages of this package.
212: */
213: public NamedIterator getInnerPackages() {
214: return new NamedIterator(children);
215: }
216:
217: /**
218: * Returns the parent package of this package.
219: */
220: public Package getParentPackage() {
221: return getPackage();
222: }
223:
224: /**
225: * Add this package to its parent package <code>p</code>.
226: */
227: public void addToPackage(Package p) {
228: if (this .getName().startsWith(p.getName())) // legal to insert?
229: {
230: if (p.getName().equals(getName())) // target is same package
231: {
232: // add all classes in this package
233: NamedIterator classes = getClasses();
234: while (classes.hasMore()) {
235: p.add((Class) classes.next());
236: }
237: // add child packages
238: NamedIterator packages = getInnerPackages();
239: while (packages.hasMore()) {
240: Package inner = (Package) packages.next();
241: p.add(inner);
242: }
243: } else if (p.getName().equals(getParentPackage().getName())) // target is same as own _parent_ package
244: {
245: NamedIterator it = p.getInnerPackages();
246: Package inner = (Package) it.find(getName()); // already a sub-package with same name as this?
247: if (inner != null) {
248: inner.add(this ); // yes
249: } else {
250: p.registerPackage(this ); // no
251: }
252: } else {
253: // add own parent package instead
254: p.add(getParentPackage());
255: }
256: } else {
257: throw new IllegalArgumentException("cannot add package '"
258: + getName() + "' into package '" + p.getName()
259: + "'");
260: }
261: }
262:
263: /**
264: * Output this object as XML.
265: *
266: * @return The XML tag.
267: * @see #initFromXML
268: */
269: public Element buildXML(Document d) {
270: Element e;
271: if (!isBasePackage()) {
272: e = super .buildXML(d);
273: } else {
274: e = d.getDocumentElement();
275: }
276: NamedIterator it = getClasses();
277: while (it.hasMore()) {
278: Class c = (Class) it.next();
279: e.appendChild(c.buildXML(d));
280: }
281: it = getInnerPackages();
282: while (it.hasMore()) {
283: Package p = (Package) it.next();
284: e.appendChild(p.buildXML(d));
285: }
286: return e;
287: }
288:
289: /**
290: * Initialize this object from XML.
291: *
292: * @param element The XML tag.
293: * @throws IOException if an i/o error occurs
294: */
295: public void initFromXML(Element element) throws IOException {
296: // to be extended (not overwritten) by subclasses
297: String tagname = element.getTagName();
298: if (tagname.equals("package")) {
299: super .initFromXML(element);
300: } else if (tagname.equals("xjava")) { // special: treat <xjava> as base package tag
301: name = "";
302: } else {
303: throw new IOException("illegal tag name " + tagname
304: + " expected 'xjava' or 'package'");
305: }
306:
307: initEmptyFathers();
308:
309: // classes / interfaces
310: myClass.removeAllElements();
311:
312: // classes
313: NodeList nl = XMLToolbox.getChildren(element, "class");
314: for (int i = 0; i < nl.getLength(); i++) {
315: Class cl = new Class();
316: cl.setPackage(this );
317: cl.initFromXML((Element) nl.item(i));
318: }
319:
320: // interfaces
321: nl = XMLToolbox.getChildren(element, "interface");
322: for (int i = 0; i < nl.getLength(); i++) {
323: Class cl = new Class();
324: cl.setPackage(this );
325: cl.setInterface(true);
326: cl.initFromXML((Element) nl.item(i));
327: }
328:
329: // inner packages
330: children.removeAllElements();
331: nl = XMLToolbox.getChildren(element, "package");
332: for (int i = 0; i < nl.getLength(); i++) {
333: Package pa = new Package();
334: pa.initFromXML((Element) nl.item(i));
335: registerPackage(pa);
336: }
337: }
338:
339: /**
340: * Tests whether this represents the root package of a Java classpath.
341: * (A class C is member of the root package if you can invoke it by simply calling "java C".)
342: */
343: public boolean isBasePackage() {
344: return getName().equals("");
345: }
346:
347: /**
348: * Returns the root package.
349: */
350: public Package getBasePackage() {
351: if (isBasePackage()) {
352: return this ;
353: } else {
354: return getPackage().getBasePackage();
355: }
356: }
357:
358: /**
359: * Make sure that all parent packages exist.
360: */
361: protected void initEmptyFathers() {
362: if (!isBasePackage()) {
363: String fatherName = getParentPackageName(getName());
364: Package f = new Package();
365: f.setName(fatherName);
366: f.registerPackage(this );
367: f.initEmptyFathers();
368: myPackage = f;
369: } else {
370: myPackage = null;
371: }
372: }
373:
374: /**
375: * Add a class to this package. (Without caring about the class's own reference to <code>this</code>.)
376: */
377: void registerClass(Class c) {
378: if (!vectorContainsReference(myClass, c)) {
379: myClass.addElement(c);
380: }
381: }
382:
383: /**
384: * Add a package to this package. (Without caring about the package's own reference to <code>this</code>.)
385: */
386: void registerPackage(Package p) {
387: children.addElement(p);
388: }
389:
390: /**
391: * Initialize this object from parsed Java code.
392: */
393: void initFromAST(Node node) {
394: // to be extended (not overwritten) by subclasses
395: super .initFromAST(node);
396: initEmptyFathers();
397: }
398:
399: // ------------------------------------------------------------------------
400: // --- static methods ---
401: // ------------------------------------------------------------------------
402:
403: public static boolean isSourcePackage(Package base, String name) {
404: return (base.findPackage(name) != null);
405: }
406:
407: /**
408: * Removes the last part of the package name from the end of the
409: * qualified name string.
410: */
411: static String getParentPackageName(String n) {
412: int pos = n.lastIndexOf('.');
413: if (pos != -1) {
414: return n.substring(0, pos);
415: } else {
416: return "";
417: }
418: }
419:
420: /**
421: * Tests whether an objects <b>reference</b> is contained in the Vector.
422: * (<code>Vector.contains()</code> tests if elements match calling
423: * <code>equals()</code>.)
424: */
425: static boolean vectorContainsReference(Vector v, Object o) {
426: for (Enumeration e = v.elements(); e.hasMoreElements();) {
427: if (e.nextElement() == o) {
428: return true;
429: }
430: }
431: return false;
432: }
433:
434: } // end Package
|