KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > alt > jiapi > Rule


1 /*
2  * Copyright (C) 2001 Mika Riekkinen, Joni Suominen
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18
19 package alt.jiapi;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25
26 import java.util.regex.Pattern JavaDoc;
27 import java.util.regex.PatternSyntaxException JavaDoc;
28 //import java.util.logging.Logger;
29
import org.apache.log4j.Category;
30
31 // import org.apache.regexp.RE;
32
// import org.apache.regexp.RESyntaxException;
33

34 /**
35  * Implements a Rule in an InstrumentationDescriptor. Rules determine
36  * if a given class matches a certain InstrumentationDescriptor.
37  *
38  * <p>
39  * Rules can have wildcards.
40  *
41  * <p>
42  * Rules are ordered according to their precedence.
43  *
44  * @author Mika Riekkinen
45  * @author Joni Suominen
46  * @version $Revision: 1.16 $ $Date: 2004/03/02 07:37:11 $
47  */

48 public class Rule implements Comparable JavaDoc {
49     private static Category log = Runtime.getLogCategory(Rule.class);
50 // private Logger log = Logger.getLogger(getClass().getName());
51
private Pattern JavaDoc pattern;
52 // private RE rule;
53
private double precedence;
54     private String JavaDoc ruleString;
55
56     private int SUMS[] = { 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55 };
57
58     /**
59      * Creates a rule used used by InstrumentationDescriptor to
60      * determine whether a particular class needs to be instrumented.
61      *
62      * @param rule a rule can be a classname and it can contain wildcards
63      */

64     public Rule(String JavaDoc rule) throws JiapiException {
65         ruleString = rule;
66         StringBuffer JavaDoc _rule = new StringBuffer JavaDoc(rule);
67
68         // Replace asterixs with real regexp statements.
69
_rule = replaceText(_rule, ".", "\\.");
70         //_rule = replaceText(_rule, "*", "[a-zA-Z0-9_.-]*");
71
_rule = replaceText(_rule, "*", ".*");
72         _rule.insert(0, "^");
73         _rule.append("$");
74
75         precedence = countPrecedence(ruleString);
76          try {
77 // this.rule = new RE(_rule.toString());
78
this.pattern = Pattern.compile(_rule.toString());
79          }
80          catch (PatternSyntaxException JavaDoc se) {
81              throw new JiapiException("invalid rule syntax: " + ruleString, se);
82          }
83     }
84
85     /**
86      * Check if a given String matches this Rule.
87      * @param s String to match
88      * @return true on match, false on mismatch
89      */

90     public boolean match(String JavaDoc s) {
91         boolean b = pattern.matcher(s).matches();
92         log.debug("matching " + s + " to " + pattern.pattern() + ": " + b);
93         return b;
94         //return false;
95
}
96
97     /**
98      * Get a precedence of this Rule. Precedence determines
99      * the accuracy of a rule. The more significant rule wins over
100      * the less one. E.g. com.opensource.*.Foo is more significant
101      * than com.*.Foo since it more accurately describes the class.
102      *
103      * @return precedence
104      */

105     public double getPrecedence() {
106         return precedence;
107     }
108
109     /**
110      * Checks whether this Rule is more significant than the given Rule.
111      *
112      * @param other other Rule
113      * @return true if this Rule is more significant.
114      */

115     public boolean isMoreSignificant(Rule other) {
116         log.error("isMoreSignificant : this(" + ruleString +") " +
117                   precedence + ", other(" + other.getRuleString() +
118                   " " + other.getPrecedence());
119
120         if (compareTo(other) > 0) {
121             return true;
122         }
123
124         return false;
125     }
126
127     /**
128      * The precedence determines the order of Rules.
129      *
130      * @param o other Rule
131      */

132     public int compareTo(Object JavaDoc o) {
133         Rule other = (Rule) o;
134
135         if (precedence > other.getPrecedence()) {
136             return 1;
137         }
138
139         if (precedence < other.getPrecedence()) {
140             return -1;
141         }
142         
143         if (this.equals(other)) {
144             return 0;
145         }
146
147         // If the classes do not equal, we can't return 0. Otherwise
148
// classe's nautural ordering is not consistent with equals.
149
return -1;
150     }
151
152     /**
153      * Two rules are equal if the strings which represent them equals.
154      * (e.g. "com.* == com.*", "com.foo.* != com.*")
155      *
156      * @param o other Rule
157      */

158     public boolean equals(Object JavaDoc o) {
159         if (o instanceof Rule) {
160             return ruleString.equals(((Rule) o).getRuleString());
161         }
162
163         return false;
164     }
165
166     public int hashCode() {
167         return ruleString.hashCode();
168     }
169
170     public String JavaDoc toString() {
171         return ruleString;
172     }
173
174     /**
175      * Get a rule as a String.
176      */

177     String JavaDoc getRuleString() {
178         return ruleString;
179     }
180
181     /**
182      * Replaces "old" with "replace" in a given StringBuffer.
183      */

184     private StringBuffer JavaDoc replaceText(StringBuffer JavaDoc sb, String JavaDoc old,
185                                      String JavaDoc replace) {
186         int a = sb.length();
187         String JavaDoc s = sb.toString();
188         int len = old.length();
189         while (a >= 0) {
190             a = s.lastIndexOf(old, a);
191             if (a >= 0) {
192                 sb.replace(a, a + len, replace);
193                 a -= len;
194             }
195         }
196         
197         return sb;
198     }
199
200     /**
201      * Counts a precedence value for a rule. The function is designed
202      * so that the maximum value is 1.0. The function will get its
203      * maximum value when there's no wildcards in a rule, that is
204      * the rule accurately determines a class (com.opensource.Foo).
205      * Every wildcard in a rule decreases the precedence value.
206      * For example, if a rule is:
207      * com.opensource.*.Foo
208      * the function will be:
209      * 4/10 + 3/10 + 0 + 1/10
210      *
211      * and for rule:
212      * com.*.opensource.Foo
213      * it will be:
214      * 4/10 + 0 + 2/10 + 1/10
215      *
216      * The divider will be a sum function of the number of elements
217      * in a rule (in above examples SUM(4) = 4 + 3 + 2 + 1 = 10).
218      * The denominator is elements sequence number in a reverse order.
219      *
220      * @param r a rule
221      */

222     private double countPrecedence(String JavaDoc r) {
223         double s = 0.0;
224
225         List JavaDoc parts = new ArrayList JavaDoc();
226         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(r, ".");
227         while (st.hasMoreTokens()) {
228             parts.add(st.nextToken());
229         }
230
231         int divider = countSum(parts.size());
232         int j = parts.size();
233         for (Iterator JavaDoc i = parts.iterator(); i.hasNext(); j--) {
234             String JavaDoc part = (String JavaDoc) i.next();
235
236             if (part.indexOf('*') != -1) {
237                 continue;
238             }
239
240             s += (((double) j) / divider);
241         }
242         
243         return s;
244     }
245
246     /**
247      * Calculates a sum function. E.g. n = 5: 5 + 4 + 3 + 2 + 1 = 15
248      */

249     private int countSum(int n) {
250         if (n < 0) {
251             throw new RuntimeException JavaDoc("invalid argument:" + n);
252         }
253
254         if (n <= 10) {
255             return SUMS[n];
256         }
257         
258         int total = 0;
259         for (int i = 1; i < n; i++) {
260             total += i;
261         }
262
263         return total;
264     }
265 }
266
Popular Tags