001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.strip;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.context.*;
027: import EDU.purdue.cs.bloat.editor.*;
028: import EDU.purdue.cs.bloat.file.*;
029: import EDU.purdue.cs.bloat.reflect.*;
030:
031: /**
032: * This class is a driver program that uses BLOAT to make a Java class file
033: * smaller by removing all non-essential information (such as debugging
034: * information) from it.
035: */
036: public class Main implements Opcode {
037: private static int VERBOSE = 0;
038:
039: private static boolean FORCE = false;
040:
041: private static boolean CLOSURE = false;
042:
043: private static final List SKIP = new ArrayList();
044:
045: private static final List ONLY = new ArrayList();
046:
047: public static void main(final String[] args) {
048: final ClassFileLoader loader = new ClassFileLoader();
049: List classes = new ArrayList();
050: boolean gotdir = false;
051:
052: for (int i = 0; i < args.length; i++) {
053: if (args[i].equals("-v") || args[i].equals("-verbose")) {
054: Main.VERBOSE++;
055: } else if (args[i].equals("-help")) {
056: Main.usage();
057: } else if (args[i].equals("-classpath")) {
058: if (++i >= args.length) {
059: Main.usage();
060: }
061:
062: final String classpath = args[i];
063: loader.setClassPath(classpath);
064: } else if (args[i].equals("-classpath/p")) {
065: if (++i >= args.length) {
066: Main.usage();
067: }
068:
069: final String classpath = args[i];
070: loader.prependClassPath(classpath);
071: } else if (args[i].equals("-skip")) {
072: if (++i >= args.length) {
073: Main.usage();
074: }
075:
076: final String pkg = args[i].replace('.', '/');
077: Main.SKIP.add(pkg);
078: } else if (args[i].equals("-only")) {
079: if (++i >= args.length) {
080: Main.usage();
081: }
082:
083: final String pkg = args[i].replace('.', '/');
084: Main.ONLY.add(pkg);
085: } else if (args[i].equals("-closure")) {
086: Main.CLOSURE = true;
087: } else if (args[i].equals("-relax-loading")) {
088: ClassHierarchy.RELAX = true;
089: } else if (args[i].equals("-f")) {
090: Main.FORCE = true;
091: } else if (args[i].startsWith("-")) {
092: Main.usage();
093: } else if (i == args.length - 1) {
094: final File f = new File(args[i]);
095:
096: if (f.exists() && !f.isDirectory()) {
097: System.err.println("No such directory: "
098: + f.getPath());
099: System.exit(2);
100: }
101:
102: loader.setOutputDir(f);
103: gotdir = true;
104: } else {
105: classes.add(args[i]);
106: }
107: }
108:
109: if (!gotdir) {
110: Main.usage();
111: }
112:
113: if (classes.size() == 0) {
114: Main.usage();
115: }
116:
117: if (Main.VERBOSE > 3) {
118: ClassFileLoader.DEBUG = true;
119: ClassEditor.DEBUG = true;
120: }
121:
122: boolean errors = false;
123:
124: final Iterator iter = classes.iterator();
125:
126: while (iter.hasNext()) {
127: final String name = (String) iter.next();
128:
129: try {
130: loader.loadClass(name);
131: } catch (final ClassNotFoundException ex) {
132: System.err.println("Couldn't find class: "
133: + ex.getMessage());
134: errors = true;
135: }
136: }
137:
138: if (errors) {
139: System.exit(1);
140: }
141:
142: final BloatContext context = new CachingBloatContext(loader,
143: classes, Main.CLOSURE);
144:
145: if (!Main.CLOSURE) {
146: final Iterator e = classes.iterator();
147:
148: while (e.hasNext()) {
149: final String name = (String) e.next();
150: try {
151: final ClassInfo info = loader.loadClass(name);
152: Main.decorateClass(context, info);
153: } catch (final ClassNotFoundException ex) {
154: System.err.println("Couldn't find class: "
155: + ex.getMessage());
156: System.exit(1);
157: }
158: }
159: } else {
160: classes = null;
161:
162: final ClassHierarchy hier = context.getHierarchy();
163:
164: final Iterator e = hier.classes().iterator();
165:
166: while (e.hasNext()) {
167: final Type t = (Type) e.next();
168:
169: if (t.isObject()) {
170: try {
171: final ClassInfo info = loader.loadClass(t
172: .className());
173: Main.decorateClass(context, info);
174: } catch (final ClassNotFoundException ex) {
175: System.err.println("Couldn't find class: "
176: + ex.getMessage());
177: System.exit(1);
178: }
179: }
180: }
181: }
182: }
183:
184: private static void usage() {
185: System.err
186: .println("Usage: java EDU.purdue.cs.bloat.decorate.Main "
187: + "\n [-options] classes output_dir"
188: + "\n"
189: + "\nwhere options include:"
190: + "\n -help print out this message"
191: + "\n -v -verbose turn on verbose mode "
192: + "(can be given multiple times)"
193: + "\n -classpath <directories separated by colons>"
194: + "\n list directories in which to look for classes"
195: + "\n -f decorate files even if up-to-date"
196: + "\n -closure recursively decorate referenced classes"
197: + "\n -relax-loading don't report errors if a class is not found"
198: + "\n -skip <class|package.*>"
199: + "\n skip the given class or package"
200: + "\n (this option can be given more than once)"
201: + "\n -only <class|package.*>"
202: + "\n skip all but the given class or package"
203: + "\n (this option can be given more than once)");
204: System.exit(0);
205: }
206:
207: private static void decorateClass(final EditorContext editor,
208: final ClassInfo info) {
209: final ClassFile classFile = (ClassFile) info;
210:
211: if (!Main.FORCE) {
212: final File source = classFile.file();
213: final File target = classFile.outputFile();
214:
215: if ((source != null) && (target != null) && source.exists()
216: && target.exists()
217: && (source.lastModified() < target.lastModified())) {
218:
219: if (Main.VERBOSE > 1) {
220: System.out.println(classFile.name()
221: + " is up to date");
222: }
223:
224: return;
225: }
226: }
227:
228: if (Main.VERBOSE > 2) {
229: classFile.print(System.out);
230: }
231:
232: final ClassEditor c = editor.editClass(info);
233:
234: boolean skip = false;
235:
236: final String name = c.type().className();
237: final String qual = c.type().qualifier() + "/*";
238:
239: // Edit only classes explicitly mentioned.
240: if (Main.ONLY.size() > 0) {
241: skip = true;
242:
243: // Only edit classes we explicitly don't name.
244: for (int i = 0; i < Main.ONLY.size(); i++) {
245: final String pkg = (String) Main.ONLY.get(i);
246:
247: if (name.equals(pkg) || qual.equals(pkg)) {
248: skip = false;
249: break;
250: }
251: }
252: }
253:
254: // Don't edit classes we explicitly skip.
255: if (!skip) {
256: for (int i = 0; i < Main.SKIP.size(); i++) {
257: final String pkg = (String) Main.SKIP.get(i);
258:
259: if (name.equals(pkg) || qual.equals(pkg)) {
260: skip = true;
261: break;
262: }
263: }
264: }
265:
266: if (skip) {
267: if (Main.VERBOSE > 0) {
268: System.out.println("Skipping " + c.type().className());
269: }
270:
271: editor.release(info);
272: return;
273: }
274:
275: if (Main.VERBOSE > 0) {
276: System.out.println("Stripping class "
277: + c.type().className());
278: }
279:
280: if (Main.VERBOSE > 2) {
281: ((ClassFile) info).print(System.out);
282: }
283:
284: final MethodInfo[] methods = c.methods();
285:
286: for (int j = 0; j < methods.length; j++) {
287: methods[j].setLineNumbers(null);
288: methods[j].setLocals(null);
289: editor.commit(methods[j]);
290: }
291:
292: editor.commit(info);
293: }
294: }
|