Skip to content

Commit

Permalink
Merge pull request #28 from cloudhubs/documentation
Browse files Browse the repository at this point in the history
Documentation
  • Loading branch information
g-goulis authored Sep 9, 2024
2 parents d89790e + 64cce21 commit 973824f
Show file tree
Hide file tree
Showing 36 changed files with 584 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,37 @@
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
* Service class for detection of antipatterns, architectural rule violations, and metrics
*/
public class DetectionService {

/**
* Column labels for violation counts and metrics
*/
private static final String[] columnLabels = new String[]{"Commit ID", "Greedy Microservices", "Hub-like Microservices", "Service Chains (MS level)", "Service Chains (Method level)",
"Wrong Cuts", "Cyclic Dependencies (MS level)", "Cyclic Dependencies (Method level)", "Wobbly Service Interactions", "No Healthchecks",
"No API Gateway", "maxAIS", "avgAIS", "stdAIS", "maxADC", "ADCS", "stdADS", "maxACS", "avgACS", "stdACS", "SCF", "SIY", "maxSC", "avgSC",
"stdSC", "SCCmodularity", "maxSIDC", "avgSIDC", "stdSIDC", "maxSSIC", "avgSSIC", "stdSSIC",
"maxLOMLC", "avgLOMLC", "stdLOMLC", "AR3 (System)","AR4 (System)", "AR6 (Delta)", "AR20 (System)"};



/**
* Count of antipatterns, metrics, and architectural rules
*/
private static final int ANTIPATTERNS = 10;
private static final int METRICS = 24;
private static final int ARCHRULES = 4;

/**
* Output JSON file paths
*/
private static final String OLD_IR_PATH = "./output/OldIR.json";
private static final String DELTA_PATH = "./output/Delta.json";
private static final String NEW_IR_PATH = "./output/NewIR.json";

/**
* Detection services and parameters
*/
private final String configPath;
private final Config config;
private final GitService gitService;
Expand All @@ -61,6 +76,10 @@ public class DetectionService {
private XSSFSheet sheet;
// private final String firstCommitID

/**
* Construct with given configuration file path
* @param configPath YAML file to extract microservice details from
*/
public DetectionService(String configPath) {
this.configPath = configPath;
// Read in config
Expand All @@ -72,6 +91,9 @@ public DetectionService(String configPath) {
workbook = new XSSFWorkbook();
}

/**
* Method to detect antipatterns, architectural rule violations, and metrics
*/
public void runDetection() {

// Get list of commits
Expand Down Expand Up @@ -176,7 +198,9 @@ public void runDetection() {

}


/**
* Write headers to XSSFSheet
*/
private void writeHeaders() {
Row headerRow = sheet.createRow(0);
for (int i = 0; i < columnLabels.length; i++) {
Expand All @@ -185,14 +209,24 @@ private void writeHeaders() {
}
}

/**
* Write empty row to XSSFSheet
*
* @param rowIndex index to write row to
*/
private void writeEmptyRow(int rowIndex) {
Row row = sheet.createRow(rowIndex);
for(int i = 0; i < columnLabels.length; i++) {
row.createCell(i).setCellValue(0);
}

}

/**
* Convert iterable to a list
*
* @param iterable iterable object to convert
* @return iterable object converted to a list
*/
private List<RevCommit> iterableToList(Iterable<RevCommit> iterable) {
Iterator<RevCommit> iterator = iterable.iterator();
List<RevCommit> list = new LinkedList<>();
Expand All @@ -204,6 +238,12 @@ private List<RevCommit> iterableToList(Iterable<RevCommit> iterable) {
return list;
}

/**
* Detect antipatterns in the given microservice
*
* @param microserviceSystem microservice to scan for antipatterns
* @param allAntiPatterns map of antipattern names and integers to store antipattern counts
*/
private void detectAntipatterns(MicroserviceSystem microserviceSystem, Map<String, Integer> allAntiPatterns) {

ServiceDependencyGraph sdg = new ServiceDependencyGraph(microserviceSystem);
Expand All @@ -223,9 +263,18 @@ private void detectAntipatterns(MicroserviceSystem microserviceSystem, Map<Strin

}

/**
* Detect metrics in the given microservice
*
* @param microserviceSystem microservice to scan for antipatterns
* @param metrics map of metric names and doubles to store metric values
*/
private void detectMetrics(MicroserviceSystem microserviceSystem, Map<String, Double> metrics) {

// Create SDG
ServiceDependencyGraph sdg = new ServiceDependencyGraph(microserviceSystem);

// Degree Coupling
DegreeCoupling dc = new DegreeCoupling(sdg);
metrics.put("maxAIS", (double) dc.getMaxAIS());
metrics.put("avgAIS", dc.getAvgAIS());
Expand All @@ -238,13 +287,18 @@ private void detectMetrics(MicroserviceSystem microserviceSystem, Map<String, Do
metrics.put("stdACS", dc.getStdACS());
metrics.put("SCF", dc.getSCF());
metrics.put("SIY", (double) dc.getSIY());

// Structural Coupling
StructuralCoupling sc = new StructuralCoupling(sdg);
metrics.put("maxSC", sc.getMaxSC());
metrics.put("avgSC", sc.getAvgSC());
metrics.put("stdSC", sc.getStdSC());

// Modularity
ConnectedComponentsModularity mod = new ConnectedComponentsModularity(sdg);
metrics.put("SCCmodularity", mod.getModularity());

// Cohesion
MetricResultCalculation cohesionMetrics = RunCohesionMetrics.calculateCohesionMetrics(OLD_IR_PATH);
metrics.put("maxSIDC", cohesionMetrics.getMax("ServiceInterfaceDataCohesion"));
metrics.put("avgSIDC", cohesionMetrics.getAverage("ServiceInterfaceDataCohesion"));
Expand All @@ -258,10 +312,17 @@ private void detectMetrics(MicroserviceSystem microserviceSystem, Map<String, Do

}

/**
* Update counts of architectural rule violations in excel
*
* @param rowIndex XSSFSheet row index
* @param currARs list of architectural rule violations
*/
private void updateRules(int rowIndex, List<AbstractAR> currARs) {
int[] arcrules_counts = new int[ARCHRULES];
Arrays.fill(arcrules_counts, 0);

// Increment appropriate archrule count
if (currARs != null && !currARs.isEmpty()) {
for (AbstractAR archRule : currARs) {
if (archRule instanceof AR3) {
Expand All @@ -276,13 +337,20 @@ private void updateRules(int rowIndex, List<AbstractAR> currARs) {
}
}

// Update architectural rule counts in XSSFSheet
Row row = sheet.getRow(rowIndex);
for (int i = 0; i < arcrules_counts.length; i++) {
Cell cell = row.getCell(i + 1 + ANTIPATTERNS + METRICS); // first column is for commit ID + rest for anti-patterns+metrics
cell.setCellValue(arcrules_counts[i]);
}
}

/**
* Update antipattern counts in excel
*
* @param rowIndex XSSFSheet row index
* @param allAntiPatterns map of antipatterns to integer count
*/
private void updateAntiPatterns(int rowIndex, Map<String, Integer> allAntiPatterns) {
Row row = sheet.getRow(rowIndex);

Expand All @@ -299,6 +367,12 @@ private void updateAntiPatterns(int rowIndex, Map<String, Integer> allAntiPatter
}
}

/**
* Update metric counts in excel
*
* @param rowIndex XSSFSheet row index
* @param metrics map of metrics to double value
*/
private void updateMetrics(int rowIndex, Map<String, Double> metrics) {
Row row = sheet.getRow(rowIndex);

Expand All @@ -309,6 +383,12 @@ private void updateMetrics(int rowIndex, Map<String, Double> metrics) {
}
}

/**
* Create JSON array from list of architectural rule objects
*
* @param archRulesList list of AR objects
* @return JSON array with list entities
*/
public static JsonArray toJsonArray(List<List<AbstractAR>> archRulesList) {
JsonArray outerArray = new JsonArray();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,10 @@
package edu.university.ecs.lab.detection;

import com.google.gson.JsonArray;
import edu.university.ecs.lab.common.config.Config;
import edu.university.ecs.lab.common.config.ConfigUtil;
import edu.university.ecs.lab.common.models.ir.MicroserviceSystem;
import edu.university.ecs.lab.common.models.sdg.MethodDependencyGraph;
import edu.university.ecs.lab.common.models.sdg.ServiceDependencyGraph;
import edu.university.ecs.lab.common.services.GitService;
import edu.university.ecs.lab.common.utils.FileUtils;
import edu.university.ecs.lab.common.utils.JsonReadWriteUtils;
import edu.university.ecs.lab.delta.models.SystemChange;
import edu.university.ecs.lab.delta.services.DeltaExtractionService;
import edu.university.ecs.lab.detection.antipatterns.services.*;
import edu.university.ecs.lab.detection.architecture.models.*;
import edu.university.ecs.lab.detection.architecture.services.ARDetectionService;
import edu.university.ecs.lab.detection.metrics.RunCohesionMetrics;
import edu.university.ecs.lab.detection.metrics.models.ConnectedComponentsModularity;
import edu.university.ecs.lab.detection.metrics.models.DegreeCoupling;
import edu.university.ecs.lab.detection.metrics.models.StructuralCoupling;
import edu.university.ecs.lab.detection.metrics.services.MetricResultCalculation;
import edu.university.ecs.lab.intermediate.create.services.IRExtractionService;
import edu.university.ecs.lab.intermediate.merge.services.MergeService;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.eclipse.jgit.revwalk.RevCommit;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;

/**
* Runner class to execute detection service
*/
public class ExcelOutputRunner {


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import java.io.IOException;
import java.util.Optional;

/**
* Class to detect multiple antipatterns from IR of a given system
*/
public class AntipatternDetection {
public static void main(String[] args) {
// Create IR of first commit
Expand All @@ -22,6 +25,7 @@ public static void main(String[] args) {
// Creat Microservice System based on generated IR
MicroserviceSystem currentSystem = JsonReadWriteUtils.readFromJSON("./output/IR.json", MicroserviceSystem.class);

// Create service network graph and method network graph from Microservice System, write to JSON
ServiceDependencyGraph sdg = new ServiceDependencyGraph(currentSystem);
MethodDependencyGraph mdg = new MethodDependencyGraph(currentSystem);

Expand All @@ -30,6 +34,7 @@ public static void main(String[] args) {

int detectedAntipatterns = 0;

// Detect greedy microservices based on a default REST call threshold of 6
GreedyService greedy = new GreedyService();
GreedyMicroservice greedyMicroservices = greedy.getGreedyMicroservices(sdg);
if (!greedyMicroservices.getGreedyMicroservices().isEmpty()){
Expand All @@ -38,6 +43,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/greedy.json", greedyMicroservices.toJsonObject());
}

// Detect hublike microservices based on a default REST call threshold of 6
HubLikeService hublike = new HubLikeService();
HubLikeMicroservice hublikeMicroservices = hublike.getHubLikeMicroservice(sdg);
if (!hublikeMicroservices.getHublikeMicroservices().isEmpty()){
Expand All @@ -46,7 +52,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/hublike.json", hublikeMicroservices.toJsonObject());
}


// Detect microservice chains based on a default chain length of 3
ServiceChainMSLevelService chainService = new ServiceChainMSLevelService();
ServiceChain allChains = chainService.getServiceChains(sdg);
if (!allChains.getChain().isEmpty()){
Expand All @@ -55,6 +61,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/servicechainMSlevel.json", allChains.toJsonObject());
}

// Detect method chains based on a default chain length of 3
ServiceChainMethodLevelService chainService2 = new ServiceChainMethodLevelService();
ServiceChain allChains2 = chainService2.getServiceChains(mdg);
if (!allChains2.getChain().isEmpty()){
Expand All @@ -63,6 +70,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/servicechainMethodlevel.json", allChains2.toJsonObject());
}

// Detect clusters of wrongly interconnected services
WrongCutsService wrongCutsService = new WrongCutsService();
WrongCuts wrongCuts = wrongCutsService.detectWrongCuts(currentSystem);
if (!wrongCuts.getWrongCuts().isEmpty()){
Expand All @@ -71,6 +79,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/wrongcuts.json", wrongCuts.toJsonObject());
}

// Detect cyclic microservice dependencies
CyclicDependencyMSLevelService cycles = new CyclicDependencyMSLevelService();
CyclicDependency cycleDependencies = cycles.findCyclicDependencies(sdg);
if (!cycleDependencies.getCycles().isEmpty()){
Expand All @@ -79,6 +88,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/cyclicdependenciesMSlevel.json", cycleDependencies.toJsonObject());
}

// Detect cyclic method dependencies
CyclicDependencyMethodLevelService cycles2 = new CyclicDependencyMethodLevelService();
CyclicDependency cycleDependencies2 = cycles2.findCyclicDependencies(mdg);
if (!cycleDependencies2.getCycles().isEmpty()){
Expand All @@ -87,6 +97,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/cyclicdependenciesMethodlevel.json", cycleDependencies2.toJsonObject());
}

// Check presence of health check configurations
NoHealthcheckService noHealthCheckService = new NoHealthcheckService();
NoHealthcheck noHealthCheck = noHealthCheckService.checkHealthcheck(currentSystem);
if (!noHealthCheck.getnoHealthcheck().isEmpty()){
Expand All @@ -95,6 +106,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/nohealthcheck.json", noHealthCheck.toJsonObject());
}

// Detect wobbly microservice interactions
WobblyServiceInteractionService wobbly = new WobblyServiceInteractionService();
WobblyServiceInteraction wobblyService = wobbly.findWobblyServiceInteractions(currentSystem);
if (!wobblyService.getWobblyServiceInteractions().isEmpty()){
Expand All @@ -103,6 +115,7 @@ public static void main(String[] args) {
JsonReadWriteUtils.writeToJSON("./output/wobblyserviceinteratcions.json", wobblyService.toJsonObject());
}

// Detect the presence of API gateway configuration
NoApiGatewayService noApiGatewayService = new NoApiGatewayService();
NoApiGateway noApiGateway = noApiGatewayService.checkforApiGateway(currentSystem);
if (noApiGateway.getnoApiGateway()){
Expand All @@ -115,6 +128,12 @@ public static void main(String[] args) {

}

/**
* Method to create an IR from config file
*
* @param configPath path to configuration file
* @param fileName name of output file for IR extraction
*/
private static void createIRSystem(String configPath, String fileName) {
// Create both directories needed
FileUtils.makeDirs();
Expand All @@ -126,6 +145,13 @@ private static void createIRSystem(String configPath, String fileName) {
irExtractionService.generateIR(fileName);
}

/**
* Method to write dependency graph objects to JSON
*
* @param <T> generalized json class
* @param object json object to be written to file
* @param filename name of output JSON file
*/
public static <T> void writeObjectToJsonFile(T object, String filename) {
Gson gson = new Gson();
String json = gson.toJson(object);
Expand Down
Loading

0 comments on commit 973824f

Please sign in to comment.