001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.metrics;
034:
035: import java.util.*;
036:
037: import org.apache.log4j.*;
038:
039: import com.jeantessier.classreader.*;
040:
041: /**
042: * Collects metrics from Classfile instances.
043: *
044: * This class can only approximate SLOC based on information provided
045: * by the compiler.
046: */
047: public class MetricsGatherer extends VisitorBase {
048: private String projectName;
049: private MetricsFactory factory;
050:
051: private Collection<String> scope = null;
052: private Collection<String> filter = null;
053:
054: private Metrics currentProject;
055: private Metrics currentGroup;
056: private Metrics currentClass;
057: private Metrics currentMethod;
058:
059: private int sloc;
060: private boolean isSynthetic;
061:
062: private HashSet<MetricsListener> metricsListeners = new HashSet<MetricsListener>();
063:
064: public MetricsGatherer(String projectName, MetricsFactory factory) {
065: this .projectName = projectName;
066: this .factory = factory;
067:
068: setCurrentProject(getMetricsFactory().createProjectMetrics(
069: getProjectName()));
070: }
071:
072: public String getProjectName() {
073: return projectName;
074: }
075:
076: public MetricsFactory getMetricsFactory() {
077: return factory;
078: }
079:
080: public void setScopeIncludes(Collection<String> scope) {
081: this .scope = scope;
082: }
083:
084: public void setFilterIncludes(Collection<String> filter) {
085: this .filter = filter;
086: }
087:
088: private Metrics getCurrentProject() {
089: return currentProject;
090: }
091:
092: private void setCurrentProject(Metrics currentProject) {
093: this .currentProject = currentProject;
094: }
095:
096: private Metrics getCurrentGroup() {
097: return currentGroup;
098: }
099:
100: private void setCurrentGroup(Metrics currentGroup) {
101: this .currentGroup = currentGroup;
102: }
103:
104: private Metrics getCurrentClass() {
105: return currentClass;
106: }
107:
108: private void setCurrentClass(Metrics currentClass) {
109: this .currentClass = currentClass;
110: }
111:
112: private Metrics getCurrentMethod() {
113: return currentMethod;
114: }
115:
116: private void setCurrentMethod(Metrics currentMethod) {
117: this .currentMethod = currentMethod;
118: }
119:
120: public void visitClassfiles(Collection<Classfile> classfiles) {
121: fireBeginSession(classfiles.size());
122:
123: for (Classfile classfile : classfiles) {
124: classfile.accept(this );
125: }
126:
127: fireEndSession();
128: }
129:
130: // Classfile
131: public void visitClassfile(Classfile classfile) {
132: Logger.getLogger(getClass()).debug("VisitClassfile():");
133: Logger.getLogger(getClass()).debug(
134: " class = \"" + classfile.getClassName() + "\"");
135:
136: fireBeginClass(classfile);
137:
138: setCurrentMethod(null);
139: setCurrentClass(getMetricsFactory().createClassMetrics(
140: classfile.getClassName()));
141: setCurrentGroup(getCurrentClass().getParent());
142: setCurrentProject(getCurrentGroup().getParent());
143:
144: getMetricsFactory().includeClassMetrics(getCurrentClass());
145:
146: getCurrentProject().addToMeasurement(Metrics.PACKAGES,
147: getCurrentGroup().getName());
148:
149: if ((classfile.getAccessFlag() & Classfile.ACC_PUBLIC) != 0) {
150: getCurrentProject()
151: .addToMeasurement(Metrics.PUBLIC_CLASSES);
152: getCurrentGroup().addToMeasurement(Metrics.PUBLIC_CLASSES);
153: }
154:
155: if ((classfile.getAccessFlag() & Classfile.ACC_FINAL) != 0) {
156: getCurrentProject().addToMeasurement(Metrics.FINAL_CLASSES);
157: getCurrentGroup().addToMeasurement(Metrics.FINAL_CLASSES);
158: }
159:
160: if ((classfile.getAccessFlag() & Classfile.ACC_INTERFACE) != 0) {
161: getCurrentProject().addToMeasurement(Metrics.INTERFACES);
162: getCurrentGroup().addToMeasurement(Metrics.INTERFACES);
163: }
164:
165: if ((classfile.getAccessFlag() & Classfile.ACC_ABSTRACT) != 0) {
166: getCurrentProject().addToMeasurement(
167: Metrics.ABSTRACT_CLASSES);
168: getCurrentGroup()
169: .addToMeasurement(Metrics.ABSTRACT_CLASSES);
170: }
171:
172: if (classfile.getSuperclassIndex() != 0) {
173: classfile.getRawSuperclass().accept(this );
174:
175: Classfile super class = classfile.getLoader().getClassfile(
176: classfile.getSuperclassName());
177:
178: if (super class != null) {
179: getMetricsFactory().createClassMetrics(
180: super class.getClassName()).addToMeasurement(
181: Metrics.SUBCLASSES);
182: }
183: getCurrentClass().addToMeasurement(
184: Metrics.DEPTH_OF_INHERITANCE,
185: computeDepthOfInheritance(super class));
186: }
187:
188: for (Class_info class_info : classfile.getAllInterfaces()) {
189: class_info.accept(this );
190: }
191:
192: for (Field_info field : classfile.getAllFields()) {
193: field.accept(this );
194: }
195:
196: for (Method_info method : classfile.getAllMethods()) {
197: method.accept(this );
198: }
199:
200: sloc = 1;
201: isSynthetic = false;
202:
203: for (Attribute_info attribute : classfile.getAttributes()) {
204: attribute.accept(this );
205: }
206:
207: if (!isSynthetic) {
208: getCurrentClass()
209: .addToMeasurement(Metrics.CLASS_SLOC, sloc);
210: }
211:
212: fireEndClass(classfile, getCurrentClass());
213: }
214:
215: // ConstantPool entries
216: public void visitClass_info(Class_info entry) {
217: Logger.getLogger(getClass()).debug("VisitClass_info():");
218: Logger.getLogger(getClass()).debug(
219: " name = \"" + entry.getName() + "\"");
220: if (entry.getName().startsWith("[")) {
221: addClassDependencies(processDescriptor(entry.getName()));
222: } else {
223: addClassDependency(entry.getName());
224: }
225: }
226:
227: public void visitFieldRef_info(FieldRef_info entry) {
228: Logger.getLogger(getClass()).debug("VisitFieldRef_info():");
229: Logger.getLogger(getClass()).debug(
230: " class = \"" + entry.getClassName() + "\"");
231: Logger.getLogger(getClass()).debug(
232: " name = \"" + entry.getRawNameAndType().getName()
233: + "\"");
234: Logger.getLogger(getClass()).debug(
235: " type = \"" + entry.getRawNameAndType().getType()
236: + "\"");
237:
238: // Dependencies on attributes are accounted as dependencies on their class
239: entry.getRawClass().accept(this );
240: addClassDependencies(processDescriptor(entry
241: .getRawNameAndType().getType()));
242: }
243:
244: public void visitMethodRef_info(MethodRef_info entry) {
245: Logger.getLogger(getClass()).debug("VisitMethodRef_info():");
246: Logger.getLogger(getClass()).debug(
247: " class = \"" + entry.getClassName() + "\"");
248: Logger.getLogger(getClass()).debug(
249: " name = \"" + entry.getRawNameAndType().getName()
250: + "\"");
251: Logger.getLogger(getClass()).debug(
252: " type = \"" + entry.getRawNameAndType().getType()
253: + "\"");
254: addMethodDependency(entry.getFullSignature());
255: addClassDependencies(processDescriptor(entry
256: .getRawNameAndType().getType()));
257: }
258:
259: public void visitInterfaceMethodRef_info(
260: InterfaceMethodRef_info entry) {
261: Logger.getLogger(getClass()).debug(
262: "VisitInterfaceMethodRef_info():");
263: Logger.getLogger(getClass()).debug(
264: " class = \"" + entry.getClassName() + "\"");
265: Logger.getLogger(getClass()).debug(
266: " name = \"" + entry.getRawNameAndType().getName()
267: + "\"");
268: Logger.getLogger(getClass()).debug(
269: " type = \"" + entry.getRawNameAndType().getType()
270: + "\"");
271: addMethodDependency(entry.getFullSignature());
272: addClassDependencies(processDescriptor(entry
273: .getRawNameAndType().getType()));
274: }
275:
276: public void visitField_info(Field_info entry) {
277: getCurrentClass().addToMeasurement(Metrics.ATTRIBUTES);
278:
279: Logger.getLogger(getClass()).debug(
280: "VisitField_info(" + entry.getFullSignature() + ")");
281: Logger.getLogger(getClass()).debug(
282: "Current class: " + getCurrentClass().getName());
283: Logger.getLogger(getClass()).debug(
284: "Access flag: " + entry.getAccessFlag());
285: Logger
286: .getLogger(getClass())
287: .debug(
288: "Public: "
289: + (entry.getAccessFlag() & Method_info.ACC_PUBLIC));
290: Logger
291: .getLogger(getClass())
292: .debug(
293: "Private: "
294: + (entry.getAccessFlag() & Method_info.ACC_PRIVATE));
295: Logger
296: .getLogger(getClass())
297: .debug(
298: "Protected: "
299: + (entry.getAccessFlag() & Method_info.ACC_PROTECTED));
300: Logger
301: .getLogger(getClass())
302: .debug(
303: "Static: "
304: + (entry.getAccessFlag() & Method_info.ACC_STATIC));
305:
306: if ((entry.getAccessFlag() & Field_info.ACC_PUBLIC) != 0) {
307: getCurrentClass().addToMeasurement(
308: Metrics.PUBLIC_ATTRIBUTES);
309: } else if ((entry.getAccessFlag() & Field_info.ACC_PRIVATE) != 0) {
310: getCurrentClass().addToMeasurement(
311: Metrics.PRIVATE_ATTRIBUTES);
312: } else if ((entry.getAccessFlag() & Field_info.ACC_PROTECTED) != 0) {
313: getCurrentClass().addToMeasurement(
314: Metrics.PROTECTED_ATTRIBUTES);
315: } else {
316: getCurrentClass().addToMeasurement(
317: Metrics.PACKAGE_ATTRIBUTES);
318: }
319:
320: if ((entry.getAccessFlag() & Field_info.ACC_STATIC) != 0) {
321: getCurrentClass().addToMeasurement(
322: Metrics.STATIC_ATTRIBUTES);
323: }
324:
325: if ((entry.getAccessFlag() & Field_info.ACC_FINAL) != 0) {
326: getCurrentClass()
327: .addToMeasurement(Metrics.FINAL_ATTRIBUTES);
328: }
329:
330: if ((entry.getAccessFlag() & Field_info.ACC_VOLATILE) != 0) {
331: getCurrentClass().addToMeasurement(
332: Metrics.VOLATILE_ATTRIBUTES);
333: }
334:
335: if ((entry.getAccessFlag() & Field_info.ACC_TRANSIENT) != 0) {
336: getCurrentClass().addToMeasurement(
337: Metrics.TRANSIENT_ATTRIBUTES);
338: }
339:
340: sloc = 1;
341: isSynthetic = false;
342:
343: super .visitField_info(entry);
344:
345: if (!isSynthetic) {
346: getCurrentClass()
347: .addToMeasurement(Metrics.CLASS_SLOC, sloc);
348: }
349:
350: addClassDependencies(processDescriptor(entry.getDescriptor()));
351: }
352:
353: public void visitMethod_info(Method_info entry) {
354: fireBeginMethod(entry);
355:
356: setCurrentMethod(getMetricsFactory().createMethodMetrics(
357: entry.getFullSignature()));
358: getMetricsFactory().includeMethodMetrics(getCurrentMethod());
359:
360: Logger.getLogger(getClass()).debug(
361: "VisitMethod_info(" + entry.getFullSignature() + ")");
362: Logger.getLogger(getClass()).debug(
363: "Current class: " + getCurrentClass().getName());
364: Logger.getLogger(getClass()).debug(
365: "Access flag: " + entry.getAccessFlag());
366: Logger
367: .getLogger(getClass())
368: .debug(
369: "Public: "
370: + (entry.getAccessFlag() & Method_info.ACC_PUBLIC));
371: Logger
372: .getLogger(getClass())
373: .debug(
374: "Private: "
375: + (entry.getAccessFlag() & Method_info.ACC_PRIVATE));
376: Logger
377: .getLogger(getClass())
378: .debug(
379: "Protected: "
380: + (entry.getAccessFlag() & Method_info.ACC_PROTECTED));
381: Logger
382: .getLogger(getClass())
383: .debug(
384: "Static: "
385: + (entry.getAccessFlag() & Method_info.ACC_STATIC));
386:
387: sloc = 0;
388: isSynthetic = false;
389:
390: if ((entry.getAccessFlag() & Method_info.ACC_PUBLIC) != 0) {
391: getCurrentClass().addToMeasurement(Metrics.PUBLIC_METHODS);
392: } else if ((entry.getAccessFlag() & Method_info.ACC_PRIVATE) != 0) {
393: getCurrentClass().addToMeasurement(Metrics.PRIVATE_METHODS);
394: } else if ((entry.getAccessFlag() & Method_info.ACC_PROTECTED) != 0) {
395: getCurrentClass().addToMeasurement(
396: Metrics.PROTECTED_METHODS);
397: } else {
398: getCurrentClass().addToMeasurement(Metrics.PACKAGE_METHODS);
399: }
400:
401: if ((entry.getAccessFlag() & Method_info.ACC_STATIC) != 0) {
402: getCurrentClass().addToMeasurement(Metrics.STATIC_METHODS);
403: }
404:
405: if ((entry.getAccessFlag() & Method_info.ACC_FINAL) != 0) {
406: getCurrentClass().addToMeasurement(Metrics.FINAL_METHODS);
407: }
408:
409: if ((entry.getAccessFlag() & Method_info.ACC_SYNCHRONIZED) != 0) {
410: getCurrentClass().addToMeasurement(
411: Metrics.SYNCHRONIZED_METHODS);
412: }
413:
414: if ((entry.getAccessFlag() & Method_info.ACC_NATIVE) != 0) {
415: getCurrentClass().addToMeasurement(Metrics.NATIVE_METHODS);
416: }
417:
418: if ((entry.getAccessFlag() & Method_info.ACC_ABSTRACT) != 0) {
419: getCurrentClass()
420: .addToMeasurement(Metrics.ABSTRACT_METHODS);
421: sloc = 1;
422: }
423:
424: getCurrentMethod().addToMeasurement(
425: Metrics.PARAMETERS,
426: SignatureHelper
427: .getParameterCount(entry.getDescriptor()));
428:
429: super .visitMethod_info(entry);
430:
431: if (!isSynthetic) {
432: getCurrentMethod().addToMeasurement(Metrics.SLOC, sloc);
433: }
434:
435: addClassDependencies(processDescriptor(entry.getDescriptor()));
436:
437: fireEndMethod(entry, getCurrentMethod());
438: }
439:
440: //
441: // Attributes
442: //
443:
444: public void visitSynthetic_attribute(Synthetic_attribute attribute) {
445: Object owner = attribute.getOwner();
446:
447: isSynthetic = true;
448:
449: if (owner instanceof Classfile) {
450: getCurrentProject().addToMeasurement(
451: Metrics.SYNTHETIC_CLASSES);
452: getCurrentGroup().addToMeasurement(
453: Metrics.SYNTHETIC_CLASSES);
454: } else if (owner instanceof Field_info) {
455: getCurrentClass().addToMeasurement(
456: Metrics.SYNTHETIC_ATTRIBUTES);
457: } else if (owner instanceof Method_info) {
458: getCurrentClass().addToMeasurement(
459: Metrics.SYNTHETIC_METHODS);
460: } else {
461: Logger.getLogger(getClass()).warn(
462: "Synthetic attribute on unknown Visitable: "
463: + owner.getClass().getName());
464: }
465: }
466:
467: public void visitDeprecated_attribute(Deprecated_attribute attribute) {
468: Object owner = attribute.getOwner();
469:
470: if (owner instanceof Classfile) {
471: getCurrentProject().addToMeasurement(
472: Metrics.DEPRECATED_CLASSES);
473: getCurrentGroup().addToMeasurement(
474: Metrics.DEPRECATED_CLASSES);
475: } else if (owner instanceof Field_info) {
476: getCurrentClass().addToMeasurement(
477: Metrics.DEPRECATED_ATTRIBUTES);
478: } else if (owner instanceof Method_info) {
479: getCurrentClass().addToMeasurement(
480: Metrics.DEPRECATED_METHODS);
481: } else {
482: Logger.getLogger(getClass()).warn(
483: "Deprecated attribute on unknown Visitable: "
484: + owner.getClass().getName());
485: }
486: }
487:
488: //
489: // Attribute helpers
490: //
491:
492: public void visitInstruction(Instruction helper) {
493: super .visitInstruction(helper);
494:
495: /*
496: * We can skip the "new" (0xbb) instruction as it is always
497: * followed by a call to the constructor method.
498: */
499:
500: switch (helper.getOpcode()) {
501: case 0xb2: // getstatic
502: case 0xb3: // putstatic
503: case 0xb4: // getfield
504: case 0xb5: // putfield
505: case 0xb6: // invokevirtual
506: case 0xb7: // invokespecial
507: case 0xb8: // invokestatic
508: case 0xb9: // invokeinterface
509: // case 0xbb: // new
510: case 0xbd: // anewarray
511: case 0xc0: // checkcast
512: case 0xc1: // instanceof
513: case 0xc5: // multianewarray
514: helper.getIndexedConstantPoolEntry().accept(this );
515: break;
516: default:
517: // Do nothing
518: break;
519: }
520: }
521:
522: public void visitExceptionHandler(ExceptionHandler helper) {
523: if (helper.getCatchTypeIndex() != 0) {
524: helper.getRawCatchType().accept(this );
525: }
526: }
527:
528: public void visitInnerClass(InnerClass helper) {
529: if ((helper.getInnerClassInfoIndex() != helper
530: .getInnerClasses().getClassfile().getClassIndex())
531: && (helper.getInnerClassInfo().startsWith(helper
532: .getInnerClasses().getClassfile()
533: .getClassName()))) {
534: getCurrentProject().addToMeasurement(Metrics.INNER_CLASSES);
535: getCurrentGroup().addToMeasurement(Metrics.INNER_CLASSES);
536: getCurrentClass().addToMeasurement(Metrics.INNER_CLASSES);
537:
538: if ((helper.getAccessFlag() & InnerClass.ACC_PUBLIC) != 0) {
539: getCurrentProject().addToMeasurement(
540: Metrics.PUBLIC_INNER_CLASSES);
541: getCurrentGroup().addToMeasurement(
542: Metrics.PUBLIC_INNER_CLASSES);
543: getCurrentClass().addToMeasurement(
544: Metrics.PUBLIC_INNER_CLASSES);
545: } else if ((helper.getAccessFlag() & InnerClass.ACC_PRIVATE) != 0) {
546: getCurrentProject().addToMeasurement(
547: Metrics.PRIVATE_INNER_CLASSES);
548: getCurrentGroup().addToMeasurement(
549: Metrics.PRIVATE_INNER_CLASSES);
550: getCurrentClass().addToMeasurement(
551: Metrics.PRIVATE_INNER_CLASSES);
552: } else if ((helper.getAccessFlag() & InnerClass.ACC_PROTECTED) != 0) {
553: getCurrentProject().addToMeasurement(
554: Metrics.PROTECTED_INNER_CLASSES);
555: getCurrentGroup().addToMeasurement(
556: Metrics.PROTECTED_INNER_CLASSES);
557: getCurrentClass().addToMeasurement(
558: Metrics.PROTECTED_INNER_CLASSES);
559: } else {
560: getCurrentProject().addToMeasurement(
561: Metrics.PACKAGE_INNER_CLASSES);
562: getCurrentGroup().addToMeasurement(
563: Metrics.PACKAGE_INNER_CLASSES);
564: getCurrentClass().addToMeasurement(
565: Metrics.PACKAGE_INNER_CLASSES);
566: }
567:
568: if ((helper.getAccessFlag() & InnerClass.ACC_STATIC) != 0) {
569: getCurrentProject().addToMeasurement(
570: Metrics.STATIC_INNER_CLASSES);
571: getCurrentGroup().addToMeasurement(
572: Metrics.STATIC_INNER_CLASSES);
573: getCurrentClass().addToMeasurement(
574: Metrics.STATIC_INNER_CLASSES);
575: }
576:
577: if ((helper.getAccessFlag() & InnerClass.ACC_FINAL) != 0) {
578: getCurrentProject().addToMeasurement(
579: Metrics.FINAL_INNER_CLASSES);
580: getCurrentGroup().addToMeasurement(
581: Metrics.FINAL_INNER_CLASSES);
582: getCurrentClass().addToMeasurement(
583: Metrics.FINAL_INNER_CLASSES);
584: }
585:
586: if ((helper.getAccessFlag() & InnerClass.ACC_ABSTRACT) != 0) {
587: getCurrentProject().addToMeasurement(
588: Metrics.ABSTRACT_INNER_CLASSES);
589: getCurrentGroup().addToMeasurement(
590: Metrics.ABSTRACT_INNER_CLASSES);
591: getCurrentClass().addToMeasurement(
592: Metrics.ABSTRACT_INNER_CLASSES);
593: }
594: }
595: }
596:
597: public void visitLineNumber(LineNumber helper) {
598: sloc++;
599: }
600:
601: public void visitLocalVariable(LocalVariable helper) {
602: getCurrentMethod().addToMeasurement(Metrics.LOCAL_VARIABLES);
603:
604: addClassDependencies(processDescriptor(helper.getDescriptor()));
605: }
606:
607: private int computeDepthOfInheritance(Classfile classfile) {
608: int result = 1;
609:
610: if (classfile != null && classfile.getSuperclassIndex() != 0) {
611: Classfile super class = classfile.getLoader().getClassfile(
612: classfile.getSuperclassName());
613: result += computeDepthOfInheritance(super class);
614: }
615:
616: return result;
617: }
618:
619: private Collection<String> processDescriptor(String str) {
620: Collection<String> result = new LinkedList<String>();
621:
622: Logger.getLogger(getClass()).debug("ProcessDescriptor: " + str);
623:
624: int currentPos = 0;
625: int startPos;
626: int endPos;
627:
628: while ((startPos = str.indexOf('L', currentPos)) != -1) {
629: if ((endPos = str.indexOf(';', startPos)) != -1) {
630: String classname = SignatureHelper.path2ClassName(str
631: .substring(startPos + 1, endPos));
632: result.add(classname);
633: currentPos = endPos + 1;
634: } else {
635: currentPos = startPos + 1;
636: }
637: }
638:
639: Logger.getLogger(getClass()).debug(
640: "ProcessDescriptor: " + result);
641:
642: return result;
643: }
644:
645: private void addClassDependencies(Collection<String> classnames) {
646: for (String classname : classnames) {
647: addClassDependency(classname);
648: }
649: }
650:
651: private void addClassDependency(String name) {
652: Logger.getLogger(getClass()).debug(
653: "AddClassDependency(\"" + name + "\") ...");
654:
655: if (!getCurrentClass().getName().equals(name)
656: && isInFilter(name)) {
657: Metrics other = getMetricsFactory()
658: .createClassMetrics(name);
659:
660: if (getCurrentMethod() != null
661: && isInScope(getCurrentMethod().getName())) {
662: Logger.getLogger(getClass()).debug(
663: "AddClassDependency "
664: + getCurrentMethod().getName() + " -> "
665: + name + " ...");
666:
667: if (getCurrentClass().getParent().equals(
668: other.getParent())) {
669: Logger.getLogger(getClass()).debug(
670: "Intra-Package ...");
671: getCurrentMethod()
672: .addToMeasurement(
673: Metrics.OUTBOUND_INTRA_PACKAGE_CLASS_DEPENDENCIES,
674: other.getName());
675: other
676: .addToMeasurement(
677: Metrics.INBOUND_INTRA_PACKAGE_METHOD_DEPENDENCIES,
678: getCurrentMethod().getName());
679: } else {
680: Logger.getLogger(getClass()).debug(
681: "Extra-Package ...");
682: getCurrentMethod()
683: .addToMeasurement(
684: Metrics.OUTBOUND_EXTRA_PACKAGE_CLASS_DEPENDENCIES,
685: other.getName());
686: other
687: .addToMeasurement(
688: Metrics.INBOUND_EXTRA_PACKAGE_METHOD_DEPENDENCIES,
689: getCurrentMethod().getName());
690: }
691: } else if (isInScope(getCurrentClass().getName())) {
692: Logger.getLogger(getClass()).debug(
693: "AddClassDependency "
694: + getCurrentClass().getName() + " -> "
695: + name + " ...");
696:
697: if (getCurrentClass().getParent().equals(
698: other.getParent())) {
699: Logger.getLogger(getClass()).debug(
700: "Intra-Package ...");
701: getCurrentClass()
702: .addToMeasurement(
703: Metrics.OUTBOUND_INTRA_PACKAGE_DEPENDENCIES,
704: other.getName());
705: other.addToMeasurement(
706: Metrics.INBOUND_INTRA_PACKAGE_DEPENDENCIES,
707: getCurrentClass().getName());
708: } else {
709: Logger.getLogger(getClass()).debug(
710: "Extra-Package ...");
711: getCurrentClass()
712: .addToMeasurement(
713: Metrics.OUTBOUND_EXTRA_PACKAGE_DEPENDENCIES,
714: other.getName());
715: other.addToMeasurement(
716: Metrics.INBOUND_EXTRA_PACKAGE_DEPENDENCIES,
717: getCurrentClass().getName());
718: }
719: }
720: }
721: }
722:
723: private void addMethodDependency(String name) {
724: Logger.getLogger(getClass()).debug(
725: "AddMethodDependency " + getCurrentMethod().getName()
726: + " -> " + name + " ...");
727:
728: if (!getCurrentMethod().getName().equals(name)
729: && isInScope(getCurrentMethod().getName())
730: && isInFilter(name)) {
731: Metrics other = getMetricsFactory().createMethodMetrics(
732: name);
733:
734: if (getCurrentClass().equals(other.getParent())) {
735: Logger.getLogger(getClass()).debug("Intra-Class ...");
736: getCurrentMethod()
737: .addToMeasurement(
738: Metrics.OUTBOUND_INTRA_CLASS_FEATURE_DEPENDENCIES,
739: other.getName());
740: other
741: .addToMeasurement(
742: Metrics.INBOUND_INTRA_CLASS_METHOD_DEPENDENCIES,
743: getCurrentMethod().getName());
744: } else if (getCurrentGroup().equals(
745: other.getParent().getParent())) {
746: Logger.getLogger(getClass()).debug("Intra-Package ...");
747: getCurrentMethod()
748: .addToMeasurement(
749: Metrics.OUTBOUND_INTRA_PACKAGE_FEATURE_DEPENDENCIES,
750: other.getName());
751: other
752: .addToMeasurement(
753: Metrics.INBOUND_INTRA_PACKAGE_METHOD_DEPENDENCIES,
754: getCurrentMethod().getName());
755: } else {
756: Logger.getLogger(getClass()).debug("Extra-Package ...");
757: getCurrentMethod()
758: .addToMeasurement(
759: Metrics.OUTBOUND_EXTRA_PACKAGE_FEATURE_DEPENDENCIES,
760: other.getName());
761: other
762: .addToMeasurement(
763: Metrics.INBOUND_EXTRA_PACKAGE_METHOD_DEPENDENCIES,
764: getCurrentMethod().getName());
765: }
766: }
767: }
768:
769: private boolean isInScope(String name) {
770: boolean result = true;
771:
772: if (scope != null) {
773: result = scope.contains(name);
774: }
775:
776: return result;
777: }
778:
779: private boolean isInFilter(String name) {
780: boolean result = true;
781:
782: if (filter != null) {
783: result = filter.contains(name);
784: }
785:
786: return result;
787: }
788:
789: public void addMetricsListener(MetricsListener listener) {
790: synchronized (metricsListeners) {
791: metricsListeners.add(listener);
792: }
793: }
794:
795: public void removeMetricsListener(MetricsListener listener) {
796: synchronized (metricsListeners) {
797: metricsListeners.remove(listener);
798: }
799: }
800:
801: protected void fireBeginSession(int size) {
802: MetricsEvent event = new MetricsEvent(this , size);
803:
804: HashSet<MetricsListener> listeners;
805: synchronized (metricsListeners) {
806: listeners = (HashSet<MetricsListener>) metricsListeners
807: .clone();
808: }
809:
810: for (MetricsListener listener : listeners) {
811: listener.beginSession(event);
812: }
813: }
814:
815: protected void fireBeginClass(Classfile classfile) {
816: MetricsEvent event = new MetricsEvent(this , classfile);
817:
818: HashSet<MetricsListener> listeners;
819: synchronized (metricsListeners) {
820: listeners = (HashSet<MetricsListener>) metricsListeners
821: .clone();
822: }
823:
824: for (MetricsListener listener : listeners) {
825: listener.beginClass(event);
826: }
827: }
828:
829: protected void fireBeginMethod(Method_info method) {
830: MetricsEvent event = new MetricsEvent(this , method);
831:
832: HashSet<MetricsListener> listeners;
833: synchronized (metricsListeners) {
834: listeners = (HashSet<MetricsListener>) metricsListeners
835: .clone();
836: }
837:
838: for (MetricsListener listener : listeners) {
839: listener.beginMethod(event);
840: }
841: }
842:
843: protected void fireEndMethod(Method_info method, Metrics metrics) {
844: MetricsEvent event = new MetricsEvent(this , method, metrics);
845:
846: HashSet<MetricsListener> listeners;
847: synchronized (metricsListeners) {
848: listeners = (HashSet<MetricsListener>) metricsListeners
849: .clone();
850: }
851:
852: for (MetricsListener listener : listeners) {
853: listener.endMethod(event);
854: }
855: }
856:
857: protected void fireEndClass(Classfile classfile, Metrics metrics) {
858: MetricsEvent event = new MetricsEvent(this , classfile, metrics);
859:
860: HashSet<MetricsListener> listeners;
861: synchronized (metricsListeners) {
862: listeners = (HashSet<MetricsListener>) metricsListeners
863: .clone();
864: }
865:
866: for (MetricsListener listener : listeners) {
867: listener.endClass(event);
868: }
869: }
870:
871: protected void fireEndSession() {
872: MetricsEvent event = new MetricsEvent(this );
873:
874: HashSet<MetricsListener> listeners;
875: synchronized (metricsListeners) {
876: listeners = (HashSet<MetricsListener>) metricsListeners
877: .clone();
878: }
879:
880: for (MetricsListener listener : listeners) {
881: listener.endSession(event);
882: }
883: }
884: }
|