001: /*
002: * Closure.java
003: *
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
005: *
006: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
007: *
008: * The contents of this file are subject to the terms of either the GNU
009: * General Public License Version 2 only ("GPL") or the Common
010: * Development and Distribution License("CDDL") (collectively, the
011: * "License"). You may not use this file except in compliance with the
012: * License. You can obtain a copy of the License at
013: * http://www.netbeans.org/cddl-gplv2.html
014: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
015: * specific language governing permissions and limitations under the
016: * License. When distributing the software, include this License Header
017: * Notice in each file and include the License file at
018: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
019: * particular file as subject to the "Classpath" exception as provided
020: * by Sun in the GPL Version 2 section of the License file that
021: * accompanied this code. If applicable, add the following below the
022: * License Header, with the fields enclosed by brackets [] replaced by
023: * your own identifying information:
024: * "Portions Copyrighted [year] [name of copyright owner]"
025: *
026: * Contributor(s):
027: *
028: * The Original Software is NetBeans. The Initial Developer of the Original
029: * Software is Sun Microsystems, Inc. Portions Copyright 2000-2001 Sun
030: * Microsystems, Inc. All Rights Reserved.
031: *
032: * If you wish your version of this file to be governed by only the CDDL
033: * or only the GPL Version 2, indicate your decision by adding
034: * "[Contributor] elects to include this software in this distribution
035: * under the [CDDL or GPL Version 2] license." If you do not indicate a
036: * single choice of license, a recipient has the option to distribute
037: * your version of this file under either the CDDL, the GPL Version 2 or
038: * to extend the choice of license to its licensees as provided above.
039: * However, if you add GPL Version 2 code and therefore, elected the GPL
040: * Version 2 license, then the option applies only if the new code is
041: * made subject to such option by the copyright holder.
042: *
043: * Contributor(s): Thomas Ball
044: *
045: * Version: $Revision$
046: */
047:
048: package org.netbeans.modules.classfile.closure;
049:
050: import org.netbeans.modules.classfile.*;
051: import java.io.*;
052: import java.lang.reflect.*;
053: import java.net.URL;
054: import java.net.URLClassLoader;
055: import java.util.*;
056:
057: /**
058: * Closure: report all classes which this file references in one
059: * way or another. Note: this utility won't find classes which are
060: * dynamically loaded.
061: *
062: * @author Thomas Ball
063: */
064: public class Closure {
065: Set<String> closure;
066: ClassLoader loader;
067:
068: Closure(ClassLoader loader) {
069: this .loader = loader;
070: }
071:
072: void buildClosure(String[] classes, boolean includeJDK,
073: boolean useFileNames) throws IOException {
074: if (closure != null)
075: return;
076: closure = new HashSet<String>();
077: Set<String> visited = new HashSet<String>();
078: Stack<ClassName> stk = new Stack<ClassName>();
079: for (String cls : classes) {
080: ClassName this CN = ClassName.getClassName(cls.replace('.',
081: '/'));
082: stk.push(this CN);
083: visited.add(this CN.getExternalName());
084:
085: while (!stk.empty()) {
086: // Add class to closure.
087: ClassName cn = stk.pop();
088: String classFile = cn.getType() + ".class";
089: InputStream is = loader.getResourceAsStream(classFile);
090: if (is == null) {
091: System.err.println("couldn't find class: "
092: + cn.getExternalName());
093: continue;
094: }
095: ClassFile cfile = new ClassFile(is);
096: if (useFileNames)
097: closure.add(classFile);
098: else
099: closure.add(cfile.getName().getExternalName());
100:
101: ConstantPool pool = cfile.getConstantPool();
102: Iterator refs = pool.getAllClassNames().iterator();
103: while (refs.hasNext()) {
104: ClassName cnRef = (ClassName) refs.next();
105: String cname = cnRef.getExternalName();
106: if (cname.indexOf('[') != -1) {
107: // skip arrays
108: } else if (!includeJDK
109: && (cname.startsWith("java.")
110: || cname.startsWith("javax.")
111: || cname.startsWith("sun.")
112: || cname
113: .startsWith("com.sun.corba")
114: || cname
115: .startsWith("com.sun.image")
116: || cname
117: .startsWith("com.sun.java.swing")
118: || cname
119: .startsWith("com.sun.naming") || cname
120: .startsWith("com.sun.security"))) {
121: // if directed, skip JDK references
122: } else {
123: boolean isNew = visited.add(cname);
124: if (isNew)
125: stk.push(cnRef);
126: }
127: }
128: }
129: }
130: }
131:
132: void dumpClosure(PrintStream out) {
133: Iterator iter = new TreeSet(closure).iterator();
134: while (iter.hasNext())
135: out.println((String) iter.next());
136: }
137:
138: Iterator dependencies() {
139: return closure.iterator();
140: }
141:
142: /**
143: * An error routine which displays the command line usage
144: * before exiting.
145: */
146: public static void usage() {
147: System.err
148: .println("usage: java Closure [-includejdk] [-filenames] <class> [ <class> ...]");
149: System.exit(1);
150: }
151:
152: public static void main(String[] args) {
153: if (args.length == 0)
154: usage();
155:
156: boolean includeJDK = false;
157: boolean useFilenames = false;
158: String classpath = null;
159: int i = 0;
160: while (i < args.length) {
161: if (args[i].equals("-includejdk"))
162: includeJDK = true;
163: else if (args[i].equals("-filenames"))
164: useFilenames = true;
165: else if (args[i].equals("-classpath")
166: && i + 1 < args.length)
167: classpath = args[++i];
168: else if (args[i].charAt(0) == '-')
169: usage();
170: else
171: break;
172: i++;
173: }
174:
175: if (i == args.length)
176: usage();
177: else {
178: try {
179: String[] classes = new String[args.length - i];
180: System.arraycopy(args, i, classes, 0, classes.length);
181: Closure c = new Closure(createLoader(classpath));
182: c.buildClosure(classes, includeJDK, useFilenames);
183: c.dumpClosure(System.out);
184: } catch (IOException e) {
185: System.err.println(e.toString());
186: }
187: }
188: }
189:
190: private static ClassLoader createLoader(String classpath)
191: throws IOException {
192: if (classpath == null)
193: return Closure.class.getClassLoader();
194:
195: try {
196: String[] paths = classpath.split(File.pathSeparator);
197: URL[] urls = new URL[paths.length];
198: for (int i = 0; i < paths.length; i++) {
199: urls[i] = new File(paths[i]).toURL();
200: }
201: return new URLClassLoader(urls);
202: } catch (Exception ex) {
203: throw new IOException(ex.toString());
204: }
205: }
206: }
|