KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jeantessier > dependency > CodeDependencyCollector


1 /*
2  * Copyright (c) 2001-2005, Jean Tessier
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of Jean Tessier nor the names of his contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */

32
33 package com.jeantessier.dependency;
34
35 import java.util.*;
36
37 import org.apache.log4j.*;
38
39 import com.jeantessier.classreader.*;
40
41 /**
42  * Traverses a Classfile and extracts dependencies from its code.
43  * Does not see dependencies on static final simple constants
44  * (basic type or String) and does not look at local variables.
45  */

46 public class CodeDependencyCollector extends CollectorBase {
47     private NodeFactory factory;
48     private Node current;
49     private HashSet dependencyListeners = new HashSet();
50
51     public CodeDependencyCollector() {
52         this(new NodeFactory());
53     }
54
55     public CodeDependencyCollector(NodeFactory factory) {
56         this.factory = factory;
57     }
58
59     public NodeFactory getFactory() {
60         return factory;
61     }
62
63     public Collection getCollection() {
64         return getFactory().getPackages().values();
65     }
66
67     public void visitClassfile(Classfile classfile) {
68         current = getFactory().createClass(classfile.getClassName(), true);
69
70         fireBeginClass(classfile.toString());
71         
72         if (classfile.getSuperclassIndex() != 0) {
73             classfile.getRawSuperclass().accept(this);
74         }
75
76         Iterator i;
77
78         i = classfile.getAllInterfaces().iterator();
79         while (i.hasNext()) {
80             ((Visitable) i.next()).accept(this);
81         }
82
83         i = classfile.getAllFields().iterator();
84         while (i.hasNext()) {
85             ((Visitable) i.next()).accept(this);
86         }
87
88         i = classfile.getAllMethods().iterator();
89         while (i.hasNext()) {
90             ((Visitable) i.next()).accept(this);
91         }
92
93         fireEndClass(classfile.toString());
94     }
95
96     public void visitClass_info(Class_info entry) {
97         Logger.getLogger(getClass()).debug("VisitClass_info():");
98         Logger.getLogger(getClass()).debug(" name = \"" + entry.getName() + "\"");
99         if (entry.getName().startsWith("[")) {
100             processDescriptor(entry.getName());
101         } else {
102             Node other = getFactory().createClass(entry.getName());
103             current.addDependency(other);
104             Logger.getLogger(getClass()).info("Class_info dependency: " + current + " --> " + other);
105             fireDependency(current, other);
106         }
107     }
108
109     public void visitFieldRef_info(FieldRef_info entry) {
110         Logger.getLogger(getClass()).debug("VisitFieldRef_info():");
111         Logger.getLogger(getClass()).debug(" class = \"" + entry.getClassName() + "\"");
112         Logger.getLogger(getClass()).debug(" name = \"" + entry.getRawNameAndType().getName() + "\"");
113         Logger.getLogger(getClass()).debug(" type = \"" + entry.getRawNameAndType().getType() + "\"");
114         Node other = getFactory().createFeature(entry.getFullSignature());
115         current.addDependency(other);
116         Logger.getLogger(getClass()).info("FieldRef_info dependency: " + current + " --> " + other);
117         fireDependency(current, other);
118
119         processDescriptor(entry.getRawNameAndType().getType());
120     }
121
122     public void visitMethodRef_info(MethodRef_info entry) {
123         Logger.getLogger(getClass()).debug("VisitMethodRef_info():");
124         Logger.getLogger(getClass()).debug(" class = \"" + entry.getClassName() + "\"");
125         Logger.getLogger(getClass()).debug(" name = \"" + entry.getRawNameAndType().getName() + "\"");
126         Logger.getLogger(getClass()).debug(" type = \"" + entry.getRawNameAndType().getType() + "\"");
127         if (!entry.isStaticInitializer()) {
128             Node other = getFactory().createFeature(entry.getFullSignature());
129             current.addDependency(other);
130             Logger.getLogger(getClass()).info("MethodRef_info dependency: " + current + " --> " + other);
131             fireDependency(current, other);
132
133             processDescriptor(entry.getRawNameAndType().getType());
134         }
135     }
136
137     public void visitInterfaceMethodRef_info(InterfaceMethodRef_info entry) {
138         Logger.getLogger(getClass()).debug("VisitInterfaceMethodRef_info():");
139         Logger.getLogger(getClass()).debug(" class = \"" + entry.getClassName() + "\"");
140         Logger.getLogger(getClass()).debug(" name = \"" + entry.getRawNameAndType().getName() + "\"");
141         Logger.getLogger(getClass()).debug(" type = \"" + entry.getRawNameAndType().getType() + "\"");
142         Node other = getFactory().createFeature(entry.getFullSignature());
143         current.addDependency(other);
144         Logger.getLogger(getClass()).info("InterfaceMethodRef_info dependency: " + current + " --> " + other);
145         fireDependency(current, other);
146
147         processDescriptor(entry.getRawNameAndType().getType());
148     }
149
150     public void visitField_info(Field_info entry) {
151         Logger.getLogger(getClass()).debug("VisitField_info():");
152         Logger.getLogger(getClass()).debug(" name = \"" + entry.getName() + "\"");
153         Logger.getLogger(getClass()).debug(" descriptor = \"" + entry.getDescriptor() + "\"");
154
155         current = getFactory().createFeature(entry.getFullSignature(), true);
156
157         processDescriptor(entry.getDescriptor());
158     
159         super.visitField_info(entry);
160     }
161
162     public void visitMethod_info(Method_info entry) {
163         Logger.getLogger(getClass()).debug("VisitMethod_info():");
164         Logger.getLogger(getClass()).debug(" name = \"" + entry.getName() + "\"");
165         Logger.getLogger(getClass()).debug(" descriptor = \"" + entry.getDescriptor() + "\"");
166     
167         current = getFactory().createFeature(entry.getFullSignature(), true);
168
169         processDescriptor(entry.getDescriptor());
170
171         super.visitMethod_info(entry);
172     }
173
174     public void visitCode_attribute(Code_attribute attribute) {
175         Logger.getLogger(getClass()).debug("VisitCode_attribute() ...");
176
177         byte[] code = attribute.getCode();
178
179         /*
180          * We can skip the "new" (0xbb) instruction as it is always
181          * followed by a call to the constructor method.
182          */

183         
184         Iterator ci = attribute.iterator();
185         while (ci.hasNext()) {
186             Instruction instr = (Instruction) ci.next();
187             switch (instr.getOpcode()) {
188                 case 0xb2: // getstatic
189
case 0xb3: // putstatic
190
case 0xb4: // getfield
191
case 0xb5: // putfield
192
case 0xb6: // invokevirtual
193
case 0xb7: // invokespecial
194
case 0xb8: // invokestatic
195
case 0xb9: // invokeinterface
196
// case 0xbb: // new
197
case 0xbd: // anewarray
198
case 0xc0: // checkcast
199
case 0xc1: // instanceof
200
case 0xc5: // multianewarray
201
int start = instr.getStart();
202                     int index = ((code[start+1] & 0xff) << 8) | (code[start+2] & 0xff);
203                     ((Visitable) attribute.getClassfile().getConstantPool().get(index)).accept(this);
204                     break;
205                 default:
206                     // Do nothing
207
break;
208             }
209         }
210
211         super.visitCode_attribute(attribute);
212     }
213
214     public void visitExceptionHandler(ExceptionHandler helper) {
215         Logger.getLogger(getClass()).debug(getClass().getName() + "VisitExceptionHandler(): " + helper);
216         
217         if (helper.getCatchTypeIndex() != 0) {
218             helper.getRawCatchType().accept(this);
219         }
220     }
221
222     private void processDescriptor(String JavaDoc str) {
223         int currentPos = 0;
224         int startPos;
225         int endPos;
226
227         while ((startPos = str.indexOf('L', currentPos)) != -1) {
228             if ((endPos = str.indexOf(';', startPos)) != -1) {
229                 String JavaDoc classname = SignatureHelper.path2ClassName(str.substring(startPos + 1, endPos));
230                 Logger.getLogger(getClass()).debug(" Adding \"" + classname + "\"");
231                 Node other = getFactory().createClass(classname);
232                 current.addDependency(other);
233                 Logger.getLogger(getClass()).info("descriptor dependency: " + current + " --> " + other);
234                 fireDependency(current, other);
235                 currentPos = endPos + 1;
236             } else {
237                 currentPos = startPos + 1;
238             }
239         }
240     }
241
242     public void addDependencyListener(DependencyListener listener) {
243         synchronized(dependencyListeners) {
244             dependencyListeners.add(listener);
245         }
246     }
247
248     public void removeDependencyListener(DependencyListener listener) {
249         synchronized(dependencyListeners) {
250             dependencyListeners.remove(listener);
251         }
252     }
253
254     protected void fireBeginSession() {
255         DependencyEvent event = new DependencyEvent(this);
256
257         HashSet listeners;
258         synchronized(dependencyListeners) {
259             listeners = (HashSet) dependencyListeners.clone();
260         }
261
262         Iterator i = listeners.iterator();
263         while(i.hasNext()) {
264             ((DependencyListener) i.next()).beginSession(event);
265         }
266     }
267     
268     protected void fireBeginClass(String JavaDoc classname) {
269         DependencyEvent event = new DependencyEvent(this, classname);
270
271         HashSet listeners;
272         synchronized(dependencyListeners) {
273             listeners = (HashSet) dependencyListeners.clone();
274         }
275
276         Iterator i = listeners.iterator();
277         while(i.hasNext()) {
278             ((DependencyListener) i.next()).beginClass(event);
279         }
280     }
281
282     protected void fireDependency(Node dependent, Node dependable) {
283         DependencyEvent event = new DependencyEvent(this, dependent, dependable);
284
285         HashSet listeners;
286         synchronized(dependencyListeners) {
287             listeners = (HashSet) dependencyListeners.clone();
288         }
289
290         Iterator i = listeners.iterator();
291         while(i.hasNext()) {
292             ((DependencyListener) i.next()).dependency(event);
293         }
294     }
295
296     protected void fireEndClass(String JavaDoc classname) {
297         DependencyEvent event = new DependencyEvent(this, classname);
298
299         HashSet listeners;
300         synchronized(dependencyListeners) {
301             listeners = (HashSet) dependencyListeners.clone();
302         }
303
304         Iterator i = listeners.iterator();
305         while(i.hasNext()) {
306             ((DependencyListener) i.next()).endClass(event);
307         }
308     }
309
310     protected void fireEndSession() {
311         DependencyEvent event = new DependencyEvent(this);
312
313         HashSet listeners;
314         synchronized(dependencyListeners) {
315             listeners = (HashSet) dependencyListeners.clone();
316         }
317
318         Iterator i = listeners.iterator();
319         while(i.hasNext()) {
320             ((DependencyListener) i.next()).endSession(event);
321         }
322     }
323 }
324
Popular Tags