1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.clirr.core;
20
21 import org.apache.bcel.classfile.JavaClass;
22
23 import java.util.ArrayList;
24 import java.util.Iterator;
25
26 /***
27 * Given a JavaClass object, determines whether or not it is "selected",
28 * based on its class or package. This is used to select subsets of the
29 * classes available in a classpath for comparison or testing purposes.
30 *
31 * @author Simon Kitching
32 */
33 public final class ClassSelector implements ClassFilter
34 {
35 /*** Class for implementing an enumeration. */
36 public static final class Mode
37 {
38 private Mode()
39 {
40 }
41 }
42
43 /*** positive selection. */
44 public static final Mode MODE_IF = new Mode();
45 /*** negative selection. */
46 public static final Mode MODE_UNLESS = new Mode();
47
48 private Mode mode;
49
50 private ArrayList packages = new ArrayList()/package-summary.html">ong> ArrayList packages = new ArrayList();
51 private ArrayList packageTrees = new ArrayList()/package-summary.html">ong> ArrayList packageTrees = new ArrayList();
52 private ArrayList classes = new ArrayList();
53
54 /***
55 * Create a selector.
56 * <p>
57 * When mode is MODE_IF then a class is "selected" if-and-only-if
58 * the class matches one of the criteria defined via the addXXX methods.
59 * In other words, the criteria specify which classes are included
60 * (selected) in the resulting class set.
61 * <p>
62 * When mode is MODE_UNLESS, then a class is "selected" unless the class
63 * matches one of the criteria defined via the addXXX methods. In other
64 * words, the criteria specify which classes are excluded from the
65 * resulting class set.
66 */
67 public ClassSelector(Mode mode)
68 {
69 this.mode = mode;
70 }
71
72 /***
73 * Matches any class which is in the named package.
74 */
75 public void addPackage(String packageName)/package-summary.html">ong> void addPackage(String packageName)
76 {
77 packages.add(packageName);
78 }
79
80 /***
81 * Matches any class which is in the named package or any subpackage of it.
82 */
83 public void addPackageTree(String packageName)/package-summary.html">ong> void addPackageTree(String packageName)
84 {
85 packages.add(packageName);
86 }
87
88 /***
89 * Matches the class with exactly this name, plus any of its inner classes.
90 */
91 public void addClass(String classname)
92 {
93 classes.add(classname);
94 }
95
96 /***
97 * Return true if this class is one selected by the criteria stored
98 * in this object.
99 */
100 public boolean isSelected(JavaClass clazz)
101 {
102 if (isAnonymousInnerClass(clazz))
103 {
104 return false;
105 }
106
107 boolean matches = matchesCriteria(clazz);
108 if (mode == MODE_IF)
109 {
110 return matches;
111 }
112 else
113 {
114 return !matches;
115 }
116 }
117
118 /***
119 * Return true if this class is an anonymous inner class.
120 * Not even developers working on a package would be interested
121 * in API changes in these classes...
122 */
123 private boolean isAnonymousInnerClass(JavaClass clazz)
124 {
125 String name = clazz.getClassName();
126 int dollarPos = name.indexOf('$');
127 if (dollarPos == -1)
128 {
129 return false;
130 }
131
132 for (int i = dollarPos + 1; i < name.length(); ++i)
133 {
134 if (!Character.isDigit(name.charAt(i)))
135 {
136 return false;
137 }
138 }
139
140
141
142 return true;
143 }
144
145 /***
146 * Return true if this class matches one of the criteria stored
147 * in this object.
148 */
149 private boolean matchesCriteria(JavaClass clazz)
150 {
151 String packageName = clazz.getPackageName();
152 if</strong> (packages.contains(packageName))
153 {
154 return true;
155 }
156
157 for (Iterator i = packageTrees.iterator(); i.hasNext();)
158 {
159 String entry = (String) i.next();
160 >if (packageName.startsWith(entry))
161 {
162 rong>if (packageName.length() == entry.length())
163 {
164
165 return true;
166 }
167
168 rong>if (packageName.charAt(entry.length()) == '.')
169 {
170 return true;
171 }
172
173
174
175 }
176 }
177
178 String className = clazz.getClassName();
179 for (Iterator i = classes.iterator(); i.hasNext();)
180 {
181 String entry = (String) i.next();
182
183 if (className.startsWith(entry))
184 {
185 if (className.length() == entry.length())
186 {
187
188 return true;
189 }
190
191 if (className.charAt(entry.length()) == '$')
192 {
193
194 return true;
195 }
196 }
197 }
198
199 return false;
200 }
201 }
202