KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > firstpartners > nounit > report > process > CallChainer


1 package net.firstpartners.nounit.report.process;
2
3 /**
4  * Title: NoUnit - Identify Classes that are not being unit Tested
5  *
6  * Copyright (C) 2001 Paul Browne , FirstPartners.net
7  *
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * @author Paul Browne
24  * @version 0.7
25  */

26
27 import java.io.File JavaDoc;
28 import java.io.FileOutputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33
34 import net.firstpartners.nounit.snippet.xml.IXmlConstants;
35 import net.firstpartners.nounit.utility.NoUnitException;
36 import net.firstpartners.nounit.utility.XmlUtil;
37
38 import org.jdom.Attribute;
39 import org.jdom.Document;
40 import org.jdom.Element;
41 import org.jdom.JDOMException;
42 import org.jdom.input.SAXBuilder;
43 import org.jdom.output.XMLOutputter;
44
45 /**
46  * Using the Start Class as a base , traces <b>all</b> calls through the
47  * document to see what calls what. Start Class is defined as any class
48  * that extends @param nameOfBaseClass. While tracing
49  * calls through the Java (XML tree) , it updates the tree, to see who
50  * calls whom, when and a what depth (and to see what this method may
51  * call in turn. <BR>
52  * This process is called the 'Call Chain'. <BR>
53  * The class acts on XML as per dtd @see nounit.dtd
54  */

55 public class CallChainer implements ICallsXmlConstants {
56     
57     /**
58      * Maximum search depth to see how an item is called
59      * Stops Infinite Loops
60      */

61     private final static int MAX_SEARCH_DEPTH=5;
62     //@todo allow this value to be passed in from the command line
63

64     /**
65      * Add Calls information to the XMl Tree (@see nounit.dtd)
66      * @param fullXMLFileName file to process
67      * @param outputFile
68      * @param nameOfBaseClass - the calls trail will run from here
69      * @exception NoUnitException
70      * @exception IOException
71      */

72     public void addCallChainInformation( File JavaDoc fullXmlFileName,
73                                          File JavaDoc outputFile,
74                                          String JavaDoc nameOfBaseClass)
75     throws NoUnitException , IOException JavaDoc , JDOMException {
76         
77         //Read in the file
78
SAXBuilder builder = new SAXBuilder();
79         Document sourceDocument = builder.build( fullXmlFileName );
80         
81         //Process the file
82
sourceDocument=lookThroughNodes( sourceDocument, nameOfBaseClass );
83         
84         //Now Delete the old outputfile , if it exists
85
if ( outputFile.exists()) {
86             outputFile.delete();
87         }
88         
89         //Get Handle to file
90
FileOutputStream JavaDoc output = new FileOutputStream JavaDoc( outputFile );
91         
92         //Output Xml to this stream
93
XMLOutputter fmt = new XMLOutputter(" ", true);
94         fmt.output( sourceDocument, output );
95     }
96     
97     /**
98      * Loops through all the nodes in the JDOM Document and processes them
99      * @param sourceDocument JDom Document to be processed
100      * @param nameOfBaseClass - the calls trail will run from here
101      * @return Document with additional information
102      */

103     private Document lookThroughNodes( Document sourceDocument,
104                                        String JavaDoc nameOfBaseClass)
105     throws JDOMException {
106         
107         //Get Handle to Nodes as HashSet
108
HashSet JavaDoc allNodes = XmlUtil.getAllNodes(sourceDocument);
109         Iterator JavaDoc nodeLoop = allNodes.iterator();
110         
111         //Loop through and add information to node
112
while (nodeLoop.hasNext()){
113             Element tmpElement=(Element)nodeLoop.next();
114             searchForExtendsTag(sourceDocument,tmpElement,nameOfBaseClass);
115         }
116         return sourceDocument;
117     }
118     
119     /**
120      * Look for one of the 'Extends' class which marks the Call chain
121      * then o the Actual Processing - starts the call chain.
122      * (i.e. marks classes as called)
123      * @param currentDocument that we are chaining within
124      * @param nameOfBaseClass - the calls trail will run from here
125      * @return Document with additional information
126      */

127     private void searchForExtendsTag( Document currentDocument,
128                                       Element inElement,
129                                       String JavaDoc nameOfBaseClass)
130     throws JDOMException {
131         
132         //Only Interested if this class is the 'Extends' tag - otherwise ignore
133
String JavaDoc tmpString = inElement.getName();
134         if( ( tmpString!=null ) &&
135             ( tmpString.equals(IXmlConstants.ELEMENT_CLASS_EXTENDS) ) ) {
136             
137             Attribute tmpAttribute =
138                 inElement.getAttribute(IXmlConstants.ATTRIBUTE_NAME);
139             String JavaDoc tmpName = tmpAttribute.getValue();
140             
141             if( (tmpName!=null ) && ( tmpName.equals(nameOfBaseClass) ) ) {
142                 startCallChain(currentDocument,inElement);
143             }
144         }
145     }
146     
147     /**
148      * Starts the call chain from this Element (ie Extends Tag)
149      * Really , it goes to the parent (Class Tag) , finds all &lt;Method&gt;
150      * children of this tag , and starts the call chain from there.
151      * @param currentDocument that we are chaining within
152      * @param inElement to start marking out calls in the XML
153      */

154     private void startCallChain(Document currentDocument, Element inElement)
155     throws JDOMException {
156         
157         //Local variables
158
int currentCallDepth =0 ; // start of call depth into document
159

160         //Get the Parent (ie Class Tag , then see all the method tags
161
Element classElement = inElement.getParent();
162         List JavaDoc possibleMethods= classElement.getChildren();
163         Iterator JavaDoc possMethodsLoop = possibleMethods.iterator();
164         
165         //Loop through possible Methods and follow all possible calls
166
while ( possMethodsLoop.hasNext() ) {
167             
168             //Get Next Element and see if it is a 'METHOD' tag
169
Element tmpMethodElement = (Element)possMethodsLoop.next();
170             String JavaDoc tmpString = tmpMethodElement.getName();
171             if( ( tmpString!=null ) &&
172                 ( tmpString.equals(IXmlConstants.ELEMENT_METHOD) ) ) {
173                 
174                 //Mark this method as being on the call chain path
175
updateNodeWithDepth( tmpMethodElement, 0 );
176                 updateNodeWithVolume( tmpMethodElement );
177                 
178                 //Now Begin Loop through sub elements of this to check
179
//for calls
180
List JavaDoc possibleCalls= tmpMethodElement.getChildren();
181                 Iterator JavaDoc possCallsLoop = possibleCalls.iterator();
182                 
183                 //Loop through possible Methods and follow all possible calls
184
while (possCallsLoop.hasNext()){
185                     
186                     //Get Next Element and see if it is a 'METHOD' tag
187
Element tmpCallsElement = (Element)possCallsLoop.next();
188                     tmpString=tmpCallsElement.getName();
189                     if( ( tmpString!=null ) &&
190                         ( tmpString.equals(IXmlConstants.ELEMENT_CALLS) ) ) {
191                                                
192                         //Now Begin Loop through sub elements of this to
193
//check for calls
194
followTheCall( currentDocument, tmpCallsElement,
195                                        currentCallDepth);
196                     }
197                 }
198             }
199         }
200     }
201     
202     
203     /**
204      * Follows the Call , marking the XML node that it finds , plus
205      * checks to see if there are any further calls from the found node /
206      * method. If so will call itself recursivly ..
207      * @param currentDocument that we are chaining within
208      * @param callsElement to start marking out calls in the XML
209      * (actual Calls Tag)
210      * @param currentSearchDepth
211      */

212     private void followTheCall( Document currentDocument, Element callsElement,
213                                 int currentSearchDepth)
214     throws JDOMException{
215         
216         //Local Variables
217
Attribute tmpAttribute;
218         String JavaDoc findClassName;
219         String JavaDoc findMethodName;
220         Element possMethodElement;
221         Element nextClassElementInChain;
222         Element nextMethodElementInChain;
223         List JavaDoc possNextMethodElementsInChain;
224         Iterator JavaDoc nextElementMethodsLoop;
225         
226         //Make copy of Current Call depth (so we can vary separately)
227
int localCallDepth=currentSearchDepth;
228         
229         
230         //Get the Class Name
231
tmpAttribute = callsElement.getAttribute(IXmlConstants.ATTRIBUTE_CLASS);
232         if(tmpAttribute==null) {return;}
233         findClassName = tmpAttribute.getValue();
234         
235         // Get the Method Name that we are looking for
236
tmpAttribute = callsElement.getAttribute(IXmlConstants.ATTRIBUTE_METHOD);
237         if(tmpAttribute==null) {return;}
238         findMethodName = tmpAttribute.getValue();
239         
240         //Use the XML Util to Search our document for the target class
241
nextClassElementInChain=XmlUtil.findNode(currentDocument,
242         IXmlConstants.ATTRIBUTE_NAME,
243         findClassName);
244         
245         //Nothing found? then this is the end of *this* chain
246
if (nextClassElementInChain==null) {return;}
247         
248         
249         //see if this has a matching method element
250
possNextMethodElementsInChain = nextClassElementInChain.getChildren(
251         IXmlConstants.ELEMENT_METHOD);
252         
253         nextElementMethodsLoop = possNextMethodElementsInChain.iterator();
254         
255         //Loop to find the matching element
256
while(nextElementMethodsLoop.hasNext()) {
257             
258             //Check to see if this is the matching (called) element
259
possMethodElement=(Element)nextElementMethodsLoop.next();
260             tmpAttribute = possMethodElement.getAttribute(IXmlConstants.ATTRIBUTE_NAME);
261             if ((tmpAttribute!=null)&&(tmpAttribute.getValue().equals(findMethodName))){
262                 
263                 
264                 //Update Attributes with Data
265
updateNodeWithDepth(possMethodElement,localCallDepth);
266                 updateNodeWithVolume(possMethodElement);
267                 
268                 //Increase current search depth
269
localCallDepth++;
270                 
271                 //Now follow any more <CALLS> tags in this method , if required
272
if (localCallDepth<MAX_SEARCH_DEPTH) {
273                     followFurtherCalls(currentDocument,possMethodElement,localCallDepth);
274                 }
275             } // end -if searched method found
276

277         } // end-while look for method
278
}
279     
280     
281     /**
282      * Checks to see if there are any futher <Calls> tags in this method , then
283      * follows them
284      * @param currentDocument that we are chaining within
285      * @param callsElement to start marking out calls in the XML (actual Calls Tag
286      * @param currentSearchDepth
287      */

288     private void followFurtherCalls(Document currentDocument,
289     Element methodElement,
290     int currentSearchDepth)
291     throws JDOMException {
292         
293         
294         
295         //Local variables
296
String JavaDoc tmpString;
297         Element tmpCallsElement;
298         List JavaDoc possibleCalls;
299         Iterator JavaDoc possCallsLoop;
300         
301         possibleCalls= methodElement.getChildren();
302         possCallsLoop = possibleCalls.iterator();
303         
304         //Loop through possible Methods and follow all possible calls
305
while (possCallsLoop.hasNext()){
306             
307             //Get Next Element and see if it is a 'CALLS' tag
308
tmpCallsElement = (Element)possCallsLoop.next();
309             tmpString=tmpCallsElement.getName();
310             if((tmpString!=null)&&(tmpString.equals(IXmlConstants.ELEMENT_CALLS))){
311                 
312                 //Do (Recursive) call to 'follow the call' (which called
313
// this method in the first place
314
followTheCall(currentDocument,tmpCallsElement,currentSearchDepth);
315                 
316             } // end if calls tag
317

318         } // end if poss calls tag
319

320     }
321     
322     
323     
324     
325     /**
326      * Updates the current (Method) Node to add call Depthdata to it
327      * @param nodeToUpdate
328      * @param currentSearchDepth
329      */

330     private void updateNodeWithDepth(Element nodeToUpdate,
331     int currentSearchDepth) {
332         //Local Variables
333
int previousCallDepth;
334         int currentCallDepth=currentSearchDepth; //default
335
Attribute tmpAttribute;
336         
337         
338         
339         //Mark the Call depth (if not already done so)
340

341         //Get current call depth , if it exists
342
try {
343             tmpAttribute = nodeToUpdate.getAttribute(ATTRIBUTE_MIN_CALL_DEPTH);
344             if (tmpAttribute!=null) {
345                 previousCallDepth=Integer.parseInt(tmpAttribute.getValue());
346                 
347                 //Compare to incoming and use existing if it is lower
348
if (currentSearchDepth>previousCallDepth){
349                     currentSearchDepth=previousCallDepth;
350                 }
351             }
352         } catch (NumberFormatException JavaDoc nfe) {
353             //Do nothing - will use incoming
354
}
355         
356         
357         //Mark Attribute with lower of the two
358
tmpAttribute = new Attribute(ATTRIBUTE_MIN_CALL_DEPTH,
359         String.valueOf(currentSearchDepth));
360         nodeToUpdate.setAttribute(tmpAttribute);
361         
362     
363         
364     }
365     
366     /**
367      * Updates the current (Method) Node to add call Volume data to it
368      * @param nodeToUpdate
369      * @param currentSearchDepth
370      */

371     private void updateNodeWithVolume(Element nodeToUpdate) {
372         //Local Variables
373
int callVolume=1; //default
374
Attribute tmpAttribute;
375         
376         
377         
378         //Mark the number of time called (if not already done so)
379

380         //Get current number of times called , if it exists
381
try {
382             tmpAttribute = nodeToUpdate.getAttribute(ATTRIBUTE_NUMBER_OF_CALLS);
383             if (tmpAttribute!=null) {
384                 callVolume=Integer.parseInt(tmpAttribute.getValue());
385                 
386                 //Increment this call volume by one
387
callVolume++;
388             }
389         } catch (NumberFormatException JavaDoc nfe) {
390             //Do Nothing - volume will default to 1
391
}
392         
393         
394         //Mark Attribute with the updated volume of calls
395
tmpAttribute = new Attribute(ATTRIBUTE_NUMBER_OF_CALLS,
396         String.valueOf(callVolume));
397         nodeToUpdate.setAttribute(tmpAttribute);
398         
399
400     }
401     
402 }
403
404
405
Popular Tags