KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > shrink > Shrinker


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */

22 package proguard.shrink;
23
24 import proguard.*;
25 import proguard.classfile.ClassPool;
26 import proguard.classfile.attribute.visitor.*;
27 import proguard.classfile.visitor.*;
28
29 import java.io.*;
30
31 /**
32  * This class shrinks class pools according to a given configuration.
33  *
34  * @author Eric Lafortune
35  */

36 public class Shrinker
37 {
38     private Configuration configuration;
39
40
41     /**
42      * Creates a new Shrinker.
43      */

44     public Shrinker(Configuration configuration)
45     {
46         this.configuration = configuration;
47     }
48
49
50     /**
51      * Performs shrinking of the given program class pool.
52      */

53     public ClassPool execute(ClassPool programClassPool,
54                              ClassPool libraryClassPool) throws IOException
55     {
56         // Check if we have at least some keep commands.
57
if (configuration.keep == null)
58         {
59             throw new IOException("You have to specify '-keep' options for the shrinking step.");
60         }
61
62         // Clean up any old visitor info.
63
programClassPool.classesAccept(new ClassCleaner());
64         libraryClassPool.classesAccept(new ClassCleaner());
65
66         // Create a visitor for marking the seeds.
67
UsageMarker usageMarker = configuration.whyAreYouKeeping == null ?
68             new UsageMarker() :
69             new ShortestUsageMarker();
70
71         ClassPoolVisitor classPoolvisitor =
72             ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
73                                                                     usageMarker,
74                                                                     usageMarker,
75                                                                     true,
76                                                                     false,
77                                                                     false);
78         // Mark the seeds.
79
programClassPool.accept(classPoolvisitor);
80         libraryClassPool.accept(classPoolvisitor);
81
82         // Mark interfaces that have to be kept.
83
programClassPool.classesAccept(new InterfaceUsageMarker(usageMarker));
84
85         // Mark the inner class and annotation information that has to be kept.
86
programClassPool.classesAccept(
87             new UsedClassFilter(usageMarker,
88             new MultiClassVisitor(new ClassVisitor[]
89             {
90                 new AllAttributeVisitor(
91                 new MultiAttributeVisitor(new AttributeVisitor[]
92                 {
93                     new InnerUsageMarker(usageMarker),
94                     new AnnotationUsageMarker(usageMarker),
95                 })),
96                 new AllMemberVisitor(
97                 new AllAttributeVisitor(
98                 new AnnotationUsageMarker(usageMarker)))
99             })));
100
101         // Should we explain ourselves?
102
if (configuration.whyAreYouKeeping != null)
103         {
104             System.out.println();
105
106             // Create a visitor for explaining classes and class members.
107
ShortestUsagePrinter shortestUsagePrinter =
108                 new ShortestUsagePrinter((ShortestUsageMarker)usageMarker,
109                                          configuration.verbose);
110
111             ClassPoolVisitor whyClassPoolvisitor =
112                 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.whyAreYouKeeping,
113                                                                         shortestUsagePrinter,
114                                                                         shortestUsagePrinter);
115
116             // Mark the seeds.
117
programClassPool.accept(whyClassPoolvisitor);
118             libraryClassPool.accept(whyClassPoolvisitor);
119         }
120
121         if (configuration.printUsage != null)
122         {
123             PrintStream ps = isFile(configuration.printUsage) ?
124                 new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) :
125                 System.out;
126
127             // Print out items that will be removed.
128
programClassPool.classesAcceptAlphabetically(
129                 new UsagePrinter(usageMarker, true, ps));
130
131             if (ps != System.out)
132             {
133                 ps.close();
134             }
135         }
136
137         // Discard unused program classes.
138
int originalProgramClassPoolSize = programClassPool.size();
139
140         ClassPool newProgramClassPool = new ClassPool();
141         programClassPool.classesAccept(
142             new UsedClassFilter(usageMarker,
143             new MultiClassVisitor(
144             new ClassVisitor[] {
145                 new ClassShrinker(usageMarker),
146                 new ClassPoolFiller(newProgramClassPool)
147             })));
148
149         programClassPool.clear();
150
151         // Check if we have at least some output classes.
152
int newProgramClassPoolSize = newProgramClassPool.size();
153         if (newProgramClassPoolSize == 0)
154         {
155             throw new IOException("The output jar is empty. Did you specify the proper '-keep' options?");
156         }
157
158         if (configuration.verbose)
159         {
160             System.out.println("Removing unused program classes and class elements...");
161             System.out.println(" Original number of program classes: " + originalProgramClassPoolSize);
162             System.out.println(" Final number of program classes: " + newProgramClassPoolSize);
163         }
164
165         return newProgramClassPool;
166     }
167
168
169     /**
170      * Returns whether the given file is actually a file, or just a placeholder
171      * for the standard output.
172      */

173     private boolean isFile(File file)
174     {
175         return file.getPath().length() > 0;
176     }
177 }
178
Popular Tags