001: /*
002: * Hammurapi
003: * Automated Java code review system.
004: * Copyright (C) 2004 Johannes Bellert
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.com
021: * e-Mail: Johannes.Bellert@ercgroup.com
022: *
023: * * Created on Apr 11, 2004
024: *
025: */
026: package org.hammurapi.inspectors.metrics;
027:
028: import java.io.FileInputStream;
029: import java.io.FileOutputStream;
030: import java.util.Collection;
031: import java.util.Enumeration;
032: import java.util.Iterator;
033: import java.util.Properties;
034:
035: import org.hammurapi.HammurapiException;
036: import org.hammurapi.InspectorBase;
037: import org.hammurapi.inspectors.metrics.callertrace.CallerTraceService;
038: import org.hammurapi.inspectors.metrics.callertrace.MethodMap;
039: import org.hammurapi.inspectors.metrics.callertrace.MethodWrapper;
040: import org.hammurapi.inspectors.metrics.callertrace.MethodWrapperDeclaration;
041: import org.hammurapi.inspectors.metrics.callertrace.MethodWrapperInvoked;
042: import org.hammurapi.results.AnnotationContext;
043: import org.hammurapi.results.LinkedAnnotation;
044: import org.w3c.dom.Document;
045: import org.w3c.dom.Element;
046:
047: import com.pavelvlasov.config.ConfigurationException;
048: import com.pavelvlasov.config.Parameterizable;
049: import com.pavelvlasov.jsel.Code;
050: import com.pavelvlasov.jsel.Constructor;
051: import com.pavelvlasov.jsel.JselException;
052: import com.pavelvlasov.jsel.LanguageElement;
053: import com.pavelvlasov.jsel.Method;
054: import com.pavelvlasov.jsel.Operation;
055: import com.pavelvlasov.jsel.OperationInfo;
056: import com.pavelvlasov.jsel.Repository;
057: import com.pavelvlasov.jsel.TypeBody;
058: import com.pavelvlasov.jsel.TypeDefinition;
059: import com.pavelvlasov.jsel.expressions.MethodCall;
060: import com.pavelvlasov.jsel.impl.AbstractRepositoryImpl;
061: import com.pavelvlasov.jsel.impl.ClassImpl;
062: import com.pavelvlasov.render.RenderRequest;
063: import com.pavelvlasov.render.dom.AbstractRenderer;
064: import com.pavelvlasov.review.SourceMarker;
065: import com.pavelvlasov.util.Acceptor;
066:
067: /**
068: * @author Johannes Bellert
069: *
070: */
071:
072: //!! move class up to caller trace package
073: public class CallerTrace extends InspectorBase implements
074: Parameterizable {
075:
076: private CallerTraceService callerTraceService = new CallerTraceService();
077:
078: //private Repository repository = null;
079:
080: public void visit(Operation methodCall) {
081: // System.out.println("*if> " + methodCall.toString());
082: }
083:
084: public void visit(MethodCall methodCall) {
085:
086: //System.out.println("*> " + methodCall.toString());
087:
088: try {
089: AbstractRepositoryImpl repository = null;
090: OperationInfo opi = methodCall.getProvider();
091: MethodWrapperInvoked mwi = new MethodWrapperInvoked(opi,
092: (SourceMarker) methodCall);
093: /*
094: if( "java.lang.StringBuffer".equals( mwi.getDeclaringType() )
095: || "java.lang.String".equals( mwi.getDeclaringType() )
096: || ( !mwi.getDeclaringType().startsWith("java.sql.")
097: && mwi.getDeclaringType().startsWith("java.") ) ){
098: */
099: Code code = ((LanguageElement) methodCall)
100: .getEnclosingCode();
101: // *> childNodes.item(i).getNodeName().equalsIgnoreCase(ApplicationConstants.LOGFILENAME
102: if (code != null && code instanceof Operation) {
103: Operation op = (Operation) code;
104: // OperationInfo provider = new OperationInfo(code);
105: TypeBody tb = code.getEnclosingType();
106: // String key = provider.getDeclaringType()+ ">>" +op.getOperationSignature();
107: String key = tb.getFcn() + ">>"
108: + op.getOperationSignature();
109:
110: //System.out.println("methodCall " + key );
111:
112: MethodMap mp = callerTraceService
113: .getAllMethodsImplemented();
114: MethodWrapperDeclaration caller = (MethodWrapperDeclaration) mp
115: .selectMethodsWithoutHashkey(key);
116:
117: // System.out.println("methodDecl of Caller " + caller.getMethodKey() );
118:
119: if (caller != null) {
120: caller.getInvokedMethods().add(mwi);
121:
122: } else {
123: // System.out.println("!!!!! methodCall without MethodWrapperDeclaration " + key );
124: }
125:
126: mwi.setCallerMethod(caller);
127: MethodWrapper invokeeDeclarationResolution = mwi;
128: MethodWrapperDeclaration invokeeDecla = (MethodWrapperDeclaration) mp
129: .selectMethodsWithoutHashkey(mwi.getMethodKey());
130:
131: if (invokeeDecla != null) {
132: // System.out.println("methodDecl of invokee " + caller.getMethodKey() );
133: invokeeDecla.setCalled();
134: invokeeDecla.afferentMethodCoupling++;
135: //System.out.println("Ma " + invokeeDecla.afferentMethodCoupling );
136: invokeeDeclarationResolution = invokeeDecla;
137:
138: } else {
139: // System.out.println("!!!!! invokeeDecla without MethodWrapperDeclaration " + mwi.getMethodKey() );
140: }
141: //!! search for implementor of methodCall and use this for reference
142: // put only methodcalls as an node, if there is no declaration
143: // issue: depending on scan relationship, the method impl may not accessable
144: callerTraceService.getAdjacencyMatrix().put(
145: invokeeDeclarationResolution.getMethodKey(),
146: caller.getMethodKey());
147: callerTraceService.getAllMethods().put(
148: mwi.getMethodKey(), mwi);
149: callerTraceService.getAllInvokedMethodTable().put(
150: mwi.getMethodKey(), mwi);
151: }
152: // if }
153: } catch (Exception e) {
154: // TODO Auto-generated catch block
155: // System.out.println( methodCall.toString() );
156: e.printStackTrace();
157: }
158: }
159:
160: public void visit(Constructor aConstructor) {
161: try {
162: Repository repository = aConstructor.getCompilationUnit()
163: .getPackage().getRepository();
164: MethodWrapperDeclaration mwd = new MethodWrapperDeclaration(
165: aConstructor.getInfo(), (SourceMarker) aConstructor);
166:
167: if (this .callerTraceService
168: .getAllInterfacesAndImplementors().containsKey(
169: mwd.getDeclaringType())) {
170: callerTraceService.getAllInterfaceOperations().add(mwd);
171: // System.out.println("added 2 allInterfaceOperations " + mwd.getMethodKey());
172: }
173:
174: callerTraceService.getAllMethods().put(mwd.getMethodKey(),
175: mwd);
176: callerTraceService.getAllMethodsImplemented().put(
177: mwd.getMethodKey(), mwd);
178: } catch (JselException e) {
179: // TODO Auto-generated catch block
180: e.printStackTrace();
181: }
182: }
183:
184: public void visit(Method methodDecl) {
185: try {
186: Repository repository = methodDecl.getCompilationUnit()
187: .getPackage().getRepository();
188: MethodWrapperDeclaration mwd = new MethodWrapperDeclaration(
189: methodDecl.getInfo(), (SourceMarker) methodDecl);
190:
191: if (this .callerTraceService
192: .getAllInterfacesAndImplementors().containsKey(
193: mwd.getDeclaringType())) {
194: callerTraceService.getAllInterfaceOperations().add(mwd);
195: // System.out.println("added 2 allInterfaceOperations " + mwd.getMethodKey());
196: }
197:
198: callerTraceService.getAllMethods().put(mwd.getMethodKey(),
199: mwd);
200: callerTraceService.getAllMethodsImplemented().put(
201: mwd.getMethodKey(), mwd);
202: } catch (JselException e) {
203: // TODO Auto-generated catch block
204: e.printStackTrace();
205: }
206: }
207:
208: public void visit(com.pavelvlasov.jsel.Interface ifc) {
209: // System.out.println("ifc: " + ifc.toString());
210:
211: final String searchTerm = ifc.getFcn();
212:
213: Repository repository = ifc.getCompilationUnit().getPackage()
214: .getRepository();
215: Collection classesOfInterest = repository
216: .findAll(new Acceptor() {
217: public boolean accept(Object element) {
218: try {
219: return (element instanceof TypeDefinition && ((TypeDefinition) element)
220: .isKindOf(searchTerm));
221: } catch (JselException e) {
222: // TODO You can put more proper handling here, e.g. throw JselRuntimeException.
223: e.printStackTrace();
224: return false;
225: }
226: }
227: });
228: if (classesOfInterest != null && classesOfInterest.size() > 0) {
229: // System.out.println("<~ " + ifc.getName() );
230: this .callerTraceService.getAllInterfacesAndImplementors()
231: .put(ifc.getName(), classesOfInterest);
232: }
233:
234: }
235:
236: //!! should be move to adj matrox
237: /*
238: * side effect: changed left-hand side node (invokees) of adjacence edges
239: */
240:
241: private void resolveInvokeesImplementors() {
242: callerTraceService.resolveInvokeesImplementors();
243: }
244:
245: /*
246: * Construct a adjacenz matrix edge between each
247: * interface operation and all the implementor operations (and only them)
248: */
249:
250: private void handleInterfaces() {
251:
252: for (int i = 0; i < this .callerTraceService
253: .getAllInterfaceOperations().size(); i++) {
254: MethodWrapperDeclaration interFaceOp = (MethodWrapperDeclaration) this .callerTraceService
255: .getAllInterfaceOperations().elementAt(i);
256: String keyIf = interFaceOp.getDeclaringType() + ">>"
257: + interFaceOp.getSignature();
258: // System.out.println( "keyIf " + keyIf );
259: Enumeration enumIF = this .callerTraceService
260: .getAllInterfacesAndImplementors().keys();
261: while (enumIF.hasMoreElements()) {
262:
263: String key = (String) enumIF.nextElement();
264: // System.out.println( "*** " + key);
265:
266: Collection classes = (Collection) this .callerTraceService
267: .getAllInterfacesAndImplementors().get(key);
268: Iterator itcls = classes.iterator();
269: while (itcls.hasNext()) {
270: // String str = (String)itcls.next();
271: Object obj = itcls.next();
272: if (obj instanceof ClassImpl) {
273: // System.out.println("+++ " + ((ClassImpl) obj).getFcn() );
274: String keyImpl = ((ClassImpl) obj).getFcn()
275: + ">>" + interFaceOp.getSignature();
276: // System.out.println("+++ keyImpl" + keyImpl );
277: // String keyImpl = ((ClassImpl) obj).getFcn()+ ">>" +interFaceOp.getName();
278: // callerTraceService.getAdjacencyMatrix().put(keyIf, keyImpl );
279: // System.out.println(this.callerTraceService.getAllMethodsImplemented());
280: MethodWrapperDeclaration mwif = (MethodWrapperDeclaration) this .callerTraceService
281: .getAllMethodsImplemented()
282: .selectMethodsWithoutHashkey(keyIf);
283: MethodWrapperDeclaration mwd = (MethodWrapperDeclaration) this .callerTraceService
284: .getAllMethodsImplemented()
285: .selectMethodsWithoutHashkey(keyImpl);
286: // System.out.println( "mwd.getMethodKey() " + mwif.getMethodKey() );
287: callerTraceService.getAdjacencyMatrix()
288: .put(mwd.getMethodKey(),
289: mwif.getMethodKey());
290: }
291: }
292: }
293:
294: }
295: }
296:
297: private void aggregate() {
298: // System.out.println("aggregate");
299: resolveInvokeesImplementors();
300: handleInterfaces();
301:
302: callerTraceService.init();
303: callerTraceService.traceCaller();
304: }
305:
306: public void leave(Repository repository) {
307: aggregate();
308:
309: context.annotate(new LinkedAnnotation() {
310: private String path;
311:
312: public String getName() {
313: return getContext().getDescriptor().getName();
314: }
315:
316: public String getPath() {
317: return path;
318: }
319:
320: public void render(AnnotationContext context)
321: throws HammurapiException {
322: String errorCausingFile = "";
323:
324: // Output images here. See AnnotationTest for details.
325:
326: class CallerTraceRenderer extends AbstractRenderer {
327: CallerTraceRenderer() {
328: super (new RenderRequest(CallerTrace.this ));
329: }
330:
331: public Element render(Document document) {
332: CallerTrace ctInspector = (CallerTrace) request
333: .getRenderee();
334:
335: Element ctInspectorElement = document
336: .createElement("CallerTrace");
337: callerTraceService.toDom(document,
338: ctInspectorElement);
339:
340: return ctInspectorElement;
341: }
342: } //-- end class NcssInspectorRenderer
343:
344: AnnotationContext.FileEntry fileEntry = context
345: .getNextFile(context.getExtension());
346: path = fileEntry.getPath();
347: // System.out.println( ".> " +this.getPath().toString() );
348:
349: AnnotationContext.FileEntry fileEntryXml = context
350: .getNextFile(".xml");
351: try {
352: CallerTraceRenderer renderer = new CallerTraceRenderer();
353: FileOutputStream out = new FileOutputStream(
354: fileEntry.getFile());
355:
356: renderer
357: .setEmbeddedStyle(context.isEmbeddedStyle());
358: try {
359: errorCausingFile = fileEntry.getFile()
360: .getAbsolutePath();
361: renderer
362: .render(
363: context.getParameter("style") == null ? null
364: : new FileInputStream(
365: context
366: .getParameter(
367: "style")
368: .toString()),
369: out);
370: } finally {
371: out.close();
372: }
373: //-- write a XML file for other XSL usage
374: FileOutputStream outXml = new FileOutputStream(
375: fileEntryXml.getFile());
376:
377: try {
378: errorCausingFile = fileEntryXml.getFile()
379: .getAbsolutePath();
380: //-- write a XML file for other XSL usage
381: renderer.setEmbeddedStyle(false);
382: renderer.render(outXml);
383: // renderer.setPrettyPrint( true );
384: // InputStream inStream=getClass().getClassLoader().getResourceAsStream(xmlResourceName);
385: // renderer.render(inStream, outXml);
386:
387: } finally {
388: outXml.close();
389: }
390: } catch (Exception e) {
391: throw new HammurapiException("Can't save "
392: + errorCausingFile + ". " + e.getMessage());
393: }
394: }
395:
396: public Properties getProperties() {
397: Properties ret = new Properties();
398: ret.setProperty("left-panel", "yes");
399: ret.setProperty("target", "Caller Trace");
400: return ret;
401: }
402: });
403: }
404:
405: /**
406: * Configures the rule. Reads in the values of the parameters XXX and
407: * class-max-complexity.
408: *
409: * @param name the name of the parameter being loaded from Hammurapi configuration
410: * @param value the value of the parameter being loaded from Hammurapi configuration
411: * @exception ConfigurationException in case of a not supported parameter
412: */
413: public boolean setParameter(String name, Object value)
414: throws ConfigurationException {
415: if (true) {
416: return true;
417: } else {
418: throw new ConfigurationException("Parameter '" + name
419: + "' is not supported");
420: }
421: }
422: }
|