KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > source > save > Measure


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.java.source.save;
20
21 import com.sun.source.tree.Tree;
22 import com.sun.source.tree.MethodTree;
23 import com.sun.source.tree.Tree;
24 import com.sun.source.tree.VariableTree;
25
26 import static com.sun.source.tree.Tree.Kind;
27
28 /**
29  * Used for distance measuring of two elements.
30  * todo (#pf): Describe mechanism.
31  *
32  * @author Martin Matula
33  * @author Tomas Hurka
34  * @author Pavel Flaska
35  */

36 class Measure {
37     
38     /**
39      * Default measure based on equals.
40      */

41     static final Measure DEFAULT = new Measure();
42     
43     /**
44      * Used for measuring distance of two <code>MethodTree</code>s.
45      * It is used also for constructors.
46      */

47     static final MethodMeasure METHOD = new MethodMeasure();
48     
49     /**
50      * Used for measuring distance of two <code>VariableTree</code>s.
51      */

52     static final VariableMeasure FIELD = new VariableMeasure();
53     
54     /**
55      * Used for measuring distance of two class members.
56      * (for fields, methods, constructors, annotation attributes etc.)
57      */

58     static final MemberMeasure MEMBER = new MemberMeasure();
59     
60     /**
61      * Used for measuring distance of two <code>VariableTree</code>s.
62      */

63     static final VariableMeasure PARAMETER = FIELD;
64
65     /**
66      * Used for measuring distance of two class names.
67      */

68     static final ClassNameMeasure CLASS_NAME = new ClassNameMeasure();
69     
70     /**
71      * Value representing infinite distance - any distance value equal
72      * or greater than this is represented as infinite (i.e. indicates
73      * that the compared objects are distinct).
74      */

75     static final int INFINITE_DISTANCE = 1000;
76     
77     /**
78      * Objects perfectly matches, they are identical.
79      */

80     static final int OBJECTS_MATCH = 0;
81     
82     /**
83      * Compares two objects and returns distance between
84      * them. (Value expressing how far they are.)
85      *
86      * @param first First object to be compared.
87      * @param second Second object to be compared.
88      * @return Distance between compared objects (0 = objects perfectly match,
89      * <code>INFINITE_DISTANCE</code> = objects are completely different)
90      */

91     int getDistance(Object JavaDoc first, Object JavaDoc second) {
92         assert first != null && second != null : "Shouldn't pass null value!";
93         
94         if (first == second || first.equals(second)) {
95             // pefectly match
96
return OBJECTS_MATCH;
97         } else {
98             // does not match
99
return INFINITE_DISTANCE;
100         }
101     }
102
103     ///////////////////////////////////////////////////////////////////////////
104
// private members
105
///////////////////////////////////////////////////////////////////////////
106
private static final StringMeasure STRING = new StringMeasure();
107     
108     // MemberMeasure
109
private static final class MemberMeasure extends Measure {
110         int getDistance(Object JavaDoc first, Object JavaDoc second) {
111             Tree t1 = (Tree) first;
112             Tree t2 = (Tree) second;
113             
114             switch (t1.getKind()) {
115                 case METHOD:
116                     return METHOD.getDistance(first, second);
117                     
118                 case VARIABLE:
119                     return FIELD.getDistance(first, second);
120                     
121                 // todo (#pf): missing implementation of other kinds of
122
// measure!
123

124                 default:
125                     return DEFAULT.getDistance(first, second);
126             }
127         }
128     }
129     
130     // MethodMeasure
131
private static final class MethodMeasure extends Measure {
132
133         private static final int NAME_WEIGHT = 60;
134         private static final int PARAMETERS_WEIGHT = 40;
135
136         int getDistance(Object JavaDoc first, Object JavaDoc second) {
137             // the object is the same...
138
if (super.getDistance(first, second) == OBJECTS_MATCH) {
139                 return OBJECTS_MATCH;
140             }
141             // they aren't the same, ensure that diff mechanism will
142
// dive inside the tree. -- There can be changes not detected
143
// by this distance mechanism, e.g. throws clause change,
144
// body changes, parameters name change etc.
145
int result = 100;
146             Tree t1 = (Tree) first;
147             Tree t2 = (Tree) second;
148             
149             // one of the object is not instance of MethodTree -- there cannot
150
// be any transformation from first to second... They are totally
151
// different
152
if (t1.getKind() != Kind.METHOD || t2.getKind() != Kind.METHOD) {
153                 return INFINITE_DISTANCE;
154             }
155             // now it is safe, both are METHOD
156
MethodTree tree1 = (MethodTree) first;
157             MethodTree tree2 = (MethodTree) second;
158             
159             // measure name distances.
160
// Note: for constructor, skip this measurement
161
if (!"<init>".contentEquals(tree1.getName()) &&
162                 !"<init>".contentEquals(tree2.getName()))
163             {
164                 result += Measure.STRING.getDistance(
165                               tree1.getName().toString(),
166                               tree2.getName().toString()
167                           ) * NAME_WEIGHT;
168             } else {
169                 result += 60000;
170             }
171
172             Tree[] types1 = new Tree[tree1.getParameters().size()];
173             Tree[] types2 = new Tree[tree2.getParameters().size()];
174             
175             int i = 0;
176             for (VariableTree item : tree1.getParameters())
177                 types1[i++] = item.getType();
178             
179             i = 0;
180             for (VariableTree item : tree2.getParameters())
181                 types2[i++] = item.getType();
182             
183             result += new OrderedArrayMeasure(Measure.CLASS_NAME).
184                         getDistance(types1, types2) * PARAMETERS_WEIGHT;
185             result /= 100;
186             return result > INFINITE_DISTANCE ? INFINITE_DISTANCE : result;
187         }
188     }
189
190     // VariableMeasure
191
private final static class VariableMeasure extends Measure {
192
193         private static final int NAME_WEIGHT = 40;
194         private static final int TYPE_WEIGHT = 60;
195
196         public int getDistance(Object JavaDoc first, Object JavaDoc second) {
197             // the object is the same...
198
if (super.getDistance(first, second) == OBJECTS_MATCH) {
199                 return OBJECTS_MATCH;
200             }
201             // they aren't the same, ensure that diff mechanism will
202
// dive inside the tree. -- There can be changes not detected
203
// by this distance mechanism, e.g. throws clause change,
204
// body changes, parameters name change etc.
205
int result = 100;
206             Tree t1 = (Tree) first;
207             Tree t2 = (Tree) second;
208             
209             // one of the object is not instance of MethodTree -- there cannot
210
// be any transformation from first to second... They are totally
211
// different
212
if (t1.getKind() != Kind.VARIABLE || t2.getKind() != Kind.VARIABLE) {
213                 return INFINITE_DISTANCE;
214             }
215             
216             VariableTree vt1 = (VariableTree) first;
217             VariableTree vt2 = (VariableTree) second;
218             
219             int nameDist = Measure.STRING.getDistance(vt1.getName().toString(), vt2.getName().toString());
220             int typeDist = Measure.CLASS_NAME.getDistance(vt1.getType(), vt2.getType());
221             
222             if (nameDist > 0 && typeDist > 0) {
223                 // do not compute the distance, both items changed, consider
224
// as a new element
225
return INFINITE_DISTANCE;
226             }
227             result += nameDist * NAME_WEIGHT;
228             result += typeDist * TYPE_WEIGHT;
229             result /= 100;
230             
231             return result > INFINITE_DISTANCE ? INFINITE_DISTANCE : result;
232         }
233     }
234     
235     // StringMeasure
236
private static final class StringMeasure extends Measure {
237         
238         private static final int SAME = 0;
239         private static final int CASE_SAME = 1;
240         private static final int DIFFERENT = 10;
241         
242         /**
243          * This method implements metrics on Strings.
244          *
245          * @param first first string
246          * @param second second string
247          * @return value between 0 and 100, where 0 means strings are
248          * identical, 100 means strings are completly different.
249          */

250         public final int getDistance(final Object JavaDoc first, final Object JavaDoc second) {
251             if (first == second)
252                 return SAME;
253             
254             if (first == null || second == null)
255                 return INFINITE_DISTANCE;
256             
257             final String JavaDoc x = (String JavaDoc) first;
258             final String JavaDoc y = (String JavaDoc) second;
259             final int xlen = x.length();
260             final int ylen = y.length();
261             int errors = 0;
262             int xindex = 0, yindex = 0;
263             final char xarr[] = new char[xlen+1];
264             final char yarr[] = new char[ylen+1];
265             
266             x.getChars(0, xlen, xarr, 0);
267             y.getChars(0, ylen, yarr, 0);
268             
269             while (xindex < xlen && yindex < ylen) {
270                 final char xchar = xarr[xindex];
271                 final char ychar = yarr[yindex];
272                 final int cherr = compareChars(xchar, ychar);
273                 
274                 if (cherr != DIFFERENT) {
275                     errors += cherr;
276                     xindex++;
277                     yindex++;
278                     continue;
279                 }
280                 final char xchar1 = xarr[xindex+1];
281                 final char ychar1 = yarr[yindex+1];
282                 if (xchar1 != 0 && ychar1 != 0) {
283                     final int cherr1 = compareChars(xchar1, ychar1);
284                     
285                     if (cherr1 != DIFFERENT) {
286                         errors += DIFFERENT + cherr1;
287                         xindex += 2;
288                         yindex += 2;
289                         continue;
290                     }
291                     final int xerr = compareChars(xchar, ychar1);
292                     final int xerr1= compareChars(xchar1, ychar);
293                     
294                     if (xerr != DIFFERENT && xerr1 != DIFFERENT) {
295                         errors += DIFFERENT + xerr + xerr1;
296                         xindex += 2;
297                         yindex += 2;
298                         continue;
299                     }
300                 }
301                 if (xlen-xindex > ylen-yindex) {
302                     xindex++;
303                 } else if (xlen-xindex < ylen-yindex) {
304                     yindex++;
305                 } else {
306                     xindex++;
307                     yindex++;
308                 }
309                 errors += DIFFERENT;
310             }
311             errors += (xlen-xindex+ylen-yindex) * DIFFERENT;
312             return (INFINITE_DISTANCE*errors)/Math.max(ylen,xlen)/DIFFERENT;
313         }
314         
315         private static final int compareChars(final char xc, final char yc) {
316             if (xc == yc)
317                 return SAME;
318             
319             char xlower = Character.toLowerCase(xc);
320             char ylower = Character.toLowerCase(yc);
321             
322             return xlower == ylower ? CASE_SAME : DIFFERENT;
323         }
324     }
325    
326     // ClassNameMeasure
327
private static final class ClassNameMeasure extends Measure {
328
329         public int getDistance(Object JavaDoc first, Object JavaDoc second) {
330             if (first == second) return OBJECTS_MATCH;
331             if (first == null || second == null) {
332                 return INFINITE_DISTANCE;
333             }
334             
335             Tree t1 = (Tree) first;
336             Tree t2 = (Tree) second;
337             
338             if (t1.getKind() == t2.getKind())
339                 // todo (#pf): check that toString() is correct here, perhaps
340
// some better mechanism should be implemented.
341
return Measure.STRING.getDistance(t1.toString(), t2.toString());
342             
343            return INFINITE_DISTANCE;
344         }
345     }
346
347     // OrderedArrayMeasure
348
private static final class OrderedArrayMeasure extends Measure {
349         
350         private final Measure measure;
351         
352         OrderedArrayMeasure(Measure elementsMeasure) {
353             measure = elementsMeasure;
354         }
355
356         public int getDistance(Object JavaDoc first, Object JavaDoc second) {
357             Object JavaDoc[] array1 = (Object JavaDoc[]) first;
358             Object JavaDoc[] array2 = (Object JavaDoc[]) second;
359             int minSize = Math.min(array1.length, array2.length);
360             int difference = Math.abs(array1.length - array2.length);
361             int result = 0;
362             
363             if (minSize == 0) {
364                 if (difference != 0)
365                     result = INFINITE_DISTANCE;
366                 return result;
367             }
368             for (int i = 0; i < minSize; i++) {
369                 result += measure.getDistance(array1[i], array2[i]);
370             }
371             result += difference * INFINITE_DISTANCE;
372             result /= (minSize+difference);
373             return result > INFINITE_DISTANCE ? INFINITE_DISTANCE : result;
374         }
375     }
376 }
377
Popular Tags