1   package com.stateofflow.eclipse.metrics.calculators.cohesion;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.eclipse.jdt.core.IType;
7   import org.eclipse.jdt.core.JavaModelException;
8   
9   import com.stateofflow.eclipse.metrics.calculators.MeasurementContext;
10  
11  final class ClassComposition {
12      private final List<FieldSet> methods = new ArrayList<FieldSet>();
13      private final FieldSet allFields = new FieldSet();
14  
15      public void addMethod(final FieldSet fields) {
16          if (fields.size() > 0) {
17              methods.add(fields);
18              allFields.addAll(fields);
19          }
20      }
21  
22      public int countMatchingMethods(final FieldSet.Predicate predicate) {
23          int count = 0;
24          for (int i = 0; i < methods.size(); i++) {
25              if (predicate.execute(methods.get(i))) {
26                  count++;
27              }
28          }
29          return count;
30      }
31  
32      private int getChidamberKemererLackOfCohesion() {
33          int noCommon = 0;
34          int common = 0;
35          for (int i = 1; i < methods.size(); i++) {
36              for (int j = 0; j < i; j++) {
37                  if (getMethod(i).intersects(getMethod(j))) {
38                      common++;
39                  } else {
40                      noCommon++;
41                  }
42              }
43          }
44  
45          return Math.max(0, noCommon - common);
46      }
47  
48      public FieldSet getFields() {
49          return allFields;
50      }
51  
52      private double getHendersonSellersLackOfCohesion() throws JavaModelException {
53          final int sumOfFieldCounts = getSumOfFieldsUsedPerMethod();
54  
55          final double averageFieldCount = ((double) sumOfFieldCounts) / allFields.size();
56          return (averageFieldCount - methods.size()) / (1 - methods.size());
57      }
58  
59      private FieldSet getMethod(final int index) {
60          return methods.get(index);
61      }
62  
63      public int getNumberOfFields() {
64          return allFields.size();
65      }
66  
67      int getNumberOfMethods() {
68          return methods.size();
69      }
70  
71      private double getPairwiseFieldIrrelation() {
72          return new PairwiseFieldIrrelationEvaluator().evaluate(this);
73      }
74  
75      private int getSumOfFieldsUsedPerMethod() {
76          int sum = 0;
77  
78          for (int i = 0; i < getNumberOfMethods(); i++) {
79              sum += getMethod(i).size();
80          }
81          return sum;
82      }
83  
84      private double getTotalCorrelation() {
85          return new TotalCorrelationEvaluator().evaluate(methods);
86      }
87  
88      private void measureChidamberKemerer(final IType measuredClass, final MeasurementContext context) throws JavaModelException {
89          context.noteTypeValue(LackOfCohesionInMethodsCalculator.CHIDAMBER_KEMERER_METRIC_ID, getChidamberKemererLackOfCohesion(), measuredClass);
90      }
91  
92      public void measureCohesion(final IType currentClass, final MeasurementContext context) throws JavaModelException {
93          if (getNumberOfMethods() > 0) {
94              measureChidamberKemerer(currentClass, context);
95              measureHendersonSellers(currentClass, context);
96              measureTotalCorrelation(currentClass, context);
97              measurePairwiseFieldIrrelation(currentClass, context);
98          }
99      }
100 
101     private void measureHendersonSellers(final IType measuredClass, final MeasurementContext context) throws JavaModelException {
102         context.noteTypeValue(LackOfCohesionInMethodsCalculator.HENDERSON_SELLERS_METRIC_ID, percentage(getHendersonSellersLackOfCohesion()), measuredClass);
103     }
104 
105     private void measurePairwiseFieldIrrelation(final IType measuredClass, final MeasurementContext context) throws JavaModelException {
106         context.noteTypeValue(LackOfCohesionInMethodsCalculator.PAIRWISE_FIELD_IRRELATION_METRIC_ID, percentage(getPairwiseFieldIrrelation()), measuredClass);
107     }
108 
109     private void measureTotalCorrelation(final IType measuredClass, final MeasurementContext context) throws JavaModelException {
110         context.noteTypeValue(LackOfCohesionInMethodsCalculator.TOTAL_CORRELATION_METRIC_ID, percentage(getTotalCorrelation()), measuredClass);
111     }
112 
113     private int percentage(final double fraction) {
114         return (int) Math.round(100.0 * fraction);
115     }
116 }
117