Skip to content

Commit

Permalink
Update OOP metrics profile
Browse files Browse the repository at this point in the history
  • Loading branch information
Muntazir Fadhel committed Nov 11, 2024
1 parent 5bdc411 commit befa52e
Show file tree
Hide file tree
Showing 16 changed files with 563 additions and 383 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>com.github.hadii-tech</groupId>
<artifactId>striff-lib</artifactId>
<packaging>jar</packaging>
<version>1.5.1</version>
<version>1.5.2</version>
<name>${project.groupId}:${project.artifactId}</name>
<description>striff-lib is a java library for generating striff diagrams.</description>
<url>https://github.com/hadii-tech/striff-lib</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ final class PUMLClassFieldsCode {
private final DiagramDisplay diagramDisplay;

PUMLClassFieldsCode(Map<String, DiagramComponent> allComponents, ChangeSet changeSet,
DiagramDisplay diagramDisplay) {
DiagramDisplay diagramDisplay) {
this.allComponents = allComponents;
this.addedComponents = changeSet.addedComponents();
this.deletedComponents = changeSet.deletedComponents();
Expand All @@ -40,8 +40,10 @@ public String value(Collection<DiagramComponent> cmps) {
List<String> componentPUMLStrings = new ArrayList<>();
if (cmp.modifiers().contains(
// Insert abstract keyword if cmp is Abstract class
OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.ABSTRACT))) {
cmpPUMLStr += (OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.ABSTRACT)
OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.ABSTRACT))) {
cmpPUMLStr += (OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.ABSTRACT)
+ " ");
}
boolean largeComponent = cmp.children().size() > MAX_ATTRIBUTE_SIZE;
Expand All @@ -52,7 +54,7 @@ public String value(Collection<DiagramComponent> cmps) {
// Insert cmp display name
if (largeComponent) {
cmpPUMLStr += cmp.name() + " <b><color:"
+ this.diagramDisplay.colorScheme().classFontColor() + ">(...)\"";
+ this.diagramDisplay.colorScheme().classFontColor() + ">(...)\"";
} else {
cmpPUMLStr += cmp.name() + "\"";
}
Expand Down Expand Up @@ -83,11 +85,11 @@ public String value(Collection<DiagramComponent> cmps) {
diagramComponent -> diagramComponent.componentType().isMethodComponent())
.collect(Collectors.toSet());
Set<DiagramComponent> fieldChilds = childComponents.stream().filter(
diagramComponent ->
diagramComponent.componentType() == OOPSourceModelConstants.ComponentType.ENUM_CONSTANT
|| diagramComponent.componentType() == OOPSourceModelConstants.ComponentType.INTERFACE_CONSTANT
|| diagramComponent.componentType()
== OOPSourceModelConstants.ComponentType.FIELD)
diagramComponent -> diagramComponent
.componentType() == OOPSourceModelConstants.ComponentType.ENUM_CONSTANT
|| diagramComponent
.componentType() == OOPSourceModelConstants.ComponentType.INTERFACE_CONSTANT
|| diagramComponent.componentType() == OOPSourceModelConstants.ComponentType.FIELD)
.collect(Collectors.toSet());
// Insert PUML text for field children
boolean zeroFields = true;
Expand Down Expand Up @@ -134,7 +136,7 @@ public String value(Collection<DiagramComponent> cmps) {
if (zeroFields && zeroMethods) {
componentPUMLStrings.add(1, componentDoc + "\n");
} else {
componentPUMLStrings.add(1, componentDoc + "\n--\n");
componentPUMLStrings.add(1, componentDoc + "--\n");
}
}
}
Expand All @@ -155,16 +157,19 @@ private String childComponentPUMLText(DiagramComponent childCmp) {
if ((childCmp.componentType() == OOPSourceModelConstants.ComponentType.METHOD)
|| childCmp.componentType().isVariableComponent()) {
if (!childCmp.componentType().isBaseComponent()) {
// if the field/method is abstract or static, add the {abstract}/{static} prefix..
// if the field/method is abstract or static, add the {abstract}/{static}
// prefix..
if (childCmp.modifiers().contains(
OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.ABSTRACT))) {
OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.ABSTRACT))) {
childCmpPUMLStr += ("{");
childCmpPUMLStr += OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.ABSTRACT);
childCmpPUMLStr += ("} ");
}
if (childCmp.modifiers().contains(
OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.STATIC))) {
OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.STATIC))) {
childCmpPUMLStr += ("{");
childCmpPUMLStr += (OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.STATIC));
Expand All @@ -187,8 +192,8 @@ private String childComponentPUMLText(DiagramComponent childCmp) {
private String getChildCmpDisplayText(DiagramComponent childCmp) {
String childCmpDisplayText = "";
if (childCmp.componentType().isMethodComponent()
|| (childCmp.componentType().isVariableComponent()
&& childCmp.componentType() != OOPSourceModelConstants.ComponentType.ENUM_CONSTANT)) {
|| (childCmp.componentType().isVariableComponent()
&& childCmp.componentType() != OOPSourceModelConstants.ComponentType.ENUM_CONSTANT)) {
childCmpDisplayText = childCmp.codeFragment();
}
if (childCmp.componentType() == OOPSourceModelConstants.ComponentType.ENUM_CONSTANT) {
Expand All @@ -200,13 +205,16 @@ private String getChildCmpDisplayText(DiagramComponent childCmp) {
private String visibilitySymbol(DiagramComponent childCmp) {
String visibilitySymbol = "";
if (childCmp.modifiers().contains(
OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.PUBLIC))) {
OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.PUBLIC))) {
visibilitySymbol += OOPSourceModelConstants.AccessModifiers.PUBLIC.getUMLClassDigramSymbol() + " ";
} else if (childCmp.modifiers().contains(
OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.PRIVATE))) {
OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.PRIVATE))) {
visibilitySymbol += OOPSourceModelConstants.AccessModifiers.PRIVATE.getUMLClassDigramSymbol() + " ";
} else if (childCmp.modifiers().contains(
OOPSourceModelConstants.getJavaAccessModifierMap().get(OOPSourceModelConstants.AccessModifiers.PROTECTED))) {
OOPSourceModelConstants.getJavaAccessModifierMap()
.get(OOPSourceModelConstants.AccessModifiers.PROTECTED))) {
visibilitySymbol += OOPSourceModelConstants.AccessModifiers.PROTECTED.getUMLClassDigramSymbol() + " ";
} else {
visibilitySymbol += OOPSourceModelConstants.AccessModifiers.NONE.getUMLClassDigramSymbol() + " ";
Expand All @@ -231,21 +239,22 @@ private String componentDocText(int docTextCharLen, DiagramComponent component)
}

/**
* Used for coloring the background of a specific child component (method, field, etc..)
* Used for coloring the background of a specific child component (method,
* field, etc..)
* within a base component.
*/
private String colorChildComponentBackground(DiagramComponent childComponent, String text) {
if (text.trim().isEmpty()) {
return text;
} else if (addedComponents.contains(childComponent)) {
return "<back:" + this.diagramDisplay.colorScheme().addedComponentColor()
+ ">" + text + "</back> ";
+ ">" + text + "</back> ";
} else if (deletedComponents.contains(childComponent)) {
return "<back:" + this.diagramDisplay.colorScheme().deletedComponentColor() + ">"
+ text + "</back> ";
+ text + "</back> ";
} else if (modifiedComponents.contains(childComponent)) {
return "<back:" + this.diagramDisplay.colorScheme().modifiedComponentColor() + ">"
+ text + "</back> ";
+ text + "</back> ";
} else {
return text;
}
Expand All @@ -257,8 +266,7 @@ private String colorChildComponentBackground(DiagramComponent childComponent, St
private String enhanceBaseCmp(DiagramComponent cmp, String text) {
String addedColor = this.diagramDisplay.colorScheme().addedComponentColor().replace("#", "");
String deletedColor = this.diagramDisplay.colorScheme().deletedComponentColor().replace("#", "");
String backgroundColorText =
"#back:" + this.diagramDisplay.colorScheme().backgroundColor().replace("#", "");
String backgroundColorText = "#back:" + this.diagramDisplay.colorScheme().backgroundColor().replace("#", "");
String headerColor = ";header:" + this.diagramDisplay.colorScheme().defaultClassHeaderColor().replace("#", "");
if (addedComponents.contains(cmp)) {
backgroundColorText = "#back:" + addedColor;
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/hadii/striff/metrics/AfferentCouplingMetric.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.hadii.striff.metrics;

import com.hadii.clarpse.reference.ComponentReference;
import com.hadii.clarpse.sourcemodel.Component;
import com.hadii.clarpse.sourcemodel.OOPSourceCodeModel;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
* Represents the Afferent Class Coupling metric, which is a measure of the
* number of classes that reference the given class.
*/
public class AfferentCouplingMetric implements Metric {

private final Map<String, Double> references = new HashMap<>();

public AfferentCouplingMetric(OOPSourceCodeModel srcModel) {
this.calculate(srcModel);
}

private void calculate(OOPSourceCodeModel srcModel) {
for (Component tempCmp : srcModel.components().collect(Collectors.toList())) {
if (tempCmp.componentType().isBaseComponent()) {
for (ComponentReference cmpRef : tempCmp
.references()) {
references.put(cmpRef.invokedComponent(),
references.getOrDefault(cmpRef.invokedComponent(), 0.0) + 1);
}
}
}
}

public double value(String cmpId) {
return this.references.getOrDefault(cmpId, 0.0);
}

@Override
public String acronym() {
return "AC";
}
}
19 changes: 0 additions & 19 deletions src/main/java/com/hadii/striff/metrics/CycloMetric.java

This file was deleted.

46 changes: 23 additions & 23 deletions src/main/java/com/hadii/striff/metrics/DITMetric.java
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
package com.hadii.striff.metrics;

import com.hadii.clarpse.reference.ComponentReference;
import com.hadii.clarpse.sourcemodel.Component;
import com.hadii.clarpse.sourcemodel.OOPSourceCodeModel;
import com.hadii.clarpse.sourcemodel.OOPSourceModelConstants;

import java.util.Optional;

/**
* Represents a Depth of Inheritance metric, which is a measure of how far down a class is declared in
* the inheritance hierarchy.
* Represents a Depth of Inheritance metric, which is a measure of how far down
* a class is declared in the inheritance hierarchy.
*/
public class DITMetric implements Metric {

private final double value;
private final OOPSourceCodeModel srcModel;

public DITMetric(Component component, OOPSourceCodeModel srcModel) {
public DITMetric(OOPSourceCodeModel srcModel) {
this.srcModel = srcModel;
this.value = calculateDit(component);
}

private int calculateDit(Component cmp) {
if (cmp.componentType() == OOPSourceModelConstants.ComponentType.INTERFACE) {
return 1;
}

int currentHighestScore = 1;

for (ComponentReference cmpRef : cmp.references(OOPSourceModelConstants.TypeReferences.EXTENSION)) {
Optional<Component> invkCmp = this.srcModel.getComponent(cmpRef.invokedComponent());
if (invkCmp.isPresent()) {
int hierarchyScore = 1 + calculateDit(invkCmp.get());
if (hierarchyScore > currentHighestScore) {
currentHighestScore = hierarchyScore;
}
}
private Double calculateDit(String cmpId) {
double currentHighestScore = 1;
Optional<Component> componentOpt = this.srcModel.getComponent(cmpId);
// Calculate the highest score if the component is present and not an interface
if (componentOpt.isPresent()
&& componentOpt.get().componentType() != OOPSourceModelConstants.ComponentType.INTERFACE) {
currentHighestScore = componentOpt.get()
.references(OOPSourceModelConstants.TypeReferences.EXTENSION).stream()
.map(cmpRef -> this.srcModel.getComponent(cmpRef.invokedComponent()))
.filter(Optional::isPresent)
.mapToDouble(invkCmp -> 1.0 + calculateDit(invkCmp.get().uniqueName()))
.max()
.orElse(currentHighestScore);
}
return currentHighestScore;
}

public double value() {
return this.value;
public double value(String cmpUniqueName) {
return this.calculateDit(cmpUniqueName);
}

@Override
public String acronym() {
return "DIT";
}
}
33 changes: 33 additions & 0 deletions src/main/java/com/hadii/striff/metrics/EfferentCouplingMetric.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.hadii.striff.metrics;

import com.hadii.clarpse.sourcemodel.Component;
import com.hadii.clarpse.sourcemodel.OOPSourceCodeModel;

import java.util.Optional;

/**
* Represents the Efferent Class Coupling metric, which is a measure of the
* number of other classes referenced by a class.
*/
public class EfferentCouplingMetric implements Metric {

private final OOPSourceCodeModel srcModel;

public EfferentCouplingMetric(OOPSourceCodeModel srcModel) {
this.srcModel = srcModel;
}

public double value(String cmpId) {
Optional<Component> componentOpt = this.srcModel.getComponent(cmpId);
if (componentOpt.isPresent()) {
return componentOpt.get().references().size();
} else {
throw new IllegalArgumentException("Could not find component: " + cmpId + "!");
}
}

@Override
public String acronym() {
return "EC";
}
}
45 changes: 45 additions & 0 deletions src/main/java/com/hadii/striff/metrics/EncapsulationMetric.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.hadii.striff.metrics;

import com.hadii.clarpse.sourcemodel.Component;
import com.hadii.clarpse.sourcemodel.OOPSourceCodeModel;

/**
* The Encapsulation Ratio measures how well a class hides its data,
* focusing on the accessibility of its fields and methods. A higher
* encapsulation ratio suggests better data hiding, which is a core
* principle of OOP.
*/
public class EncapsulationMetric implements Metric {

private OOPSourceCodeModel srcModel;

public EncapsulationMetric(OOPSourceCodeModel srcModel) {
this.srcModel = srcModel;
}

public double value(String cmpId) {
if (srcModel.containsComponent(cmpId)) {
int privateMembers = 0;
Component currComponent = srcModel.getComponent(cmpId).get();
// Iterate over children to count private/protected modifiers
for (String child : currComponent.children()) {
if (srcModel.containsComponent(child)) {
Component childCmp = srcModel.getComponent(child).get();
if (childCmp.modifiers().contains("private") || childCmp.modifiers().contains("protected")) {
privateMembers++;
}
}
}
// Avoid division by zero if there are no children
int totalChildren = currComponent.children().size();
return totalChildren > 0 ? (double) privateMembers / totalChildren : 0.0;
} else {
throw new IllegalArgumentException("Could not find component: " + cmpId + "!");
}
}

@Override
public String acronym() {
return "ENC";
}
}
Loading

0 comments on commit befa52e

Please sign in to comment.