Skip to content

Commit

Permalink
Merge pull request #4 from ArDoCo/feature/directly-load-acm-files
Browse files Browse the repository at this point in the history
Add an option to ArCoTL to load ACM Code File directly
  • Loading branch information
dfuchss authored Sep 16, 2024
2 parents 158cc58 + a79d79f commit c9c763e
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import java.io.File;
import java.util.SortedMap;

import edu.kit.kastel.mcse.ardoco.core.execution.ArDoCo;
import edu.kit.kastel.mcse.ardoco.tlr.codetraceability.SadCodeTraceabilityLinkRecovery;
import edu.kit.kastel.mcse.ardoco.core.common.util.CommonUtilities;
import edu.kit.kastel.mcse.ardoco.core.common.util.DataRepositoryHelper;
import edu.kit.kastel.mcse.ardoco.tlr.connectiongenerator.ConnectionGenerator;
import edu.kit.kastel.mcse.ardoco.core.execution.ArDoCo;
import edu.kit.kastel.mcse.ardoco.core.execution.runner.ArDoCoRunner;
import edu.kit.kastel.mcse.ardoco.tlr.codetraceability.SadCodeTraceabilityLinkRecovery;
import edu.kit.kastel.mcse.ardoco.tlr.connectiongenerator.ConnectionGenerator;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArCoTLModelProviderAgent;
import edu.kit.kastel.mcse.ardoco.tlr.recommendationgenerator.RecommendationGenerator;
import edu.kit.kastel.mcse.ardoco.tlr.text.providers.TextPreprocessingAgent;
Expand All @@ -36,7 +36,9 @@ private void definePipeline(File inputText, File inputCode, SortedMap<String, St
throw new IllegalArgumentException("Cannot deal with empty input text. Maybe there was an error reading the file.");
}
DataRepositoryHelper.putInputText(dataRepository, text);
ArCoTLModelProviderAgent arCoTLModelProviderAgent = ArCoTLModelProviderAgent.get(null, null, inputCode, additionalConfigs, dataRepository);
var codeConfiguration = ArCoTLModelProviderAgent.getCodeConfiguration(inputCode);
ArCoTLModelProviderAgent arCoTLModelProviderAgent = ArCoTLModelProviderAgent.getArCoTLModelProviderAgent(dataRepository, additionalConfigs, null,
codeConfiguration);
arDoCo.addPipelineStep(arCoTLModelProviderAgent);

arDoCo.addPipelineStep(TextPreprocessingAgent.get(additionalConfigs, dataRepository));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
import java.util.SortedMap;

import edu.kit.kastel.mcse.ardoco.core.api.models.ArchitectureModelType;
import edu.kit.kastel.mcse.ardoco.core.common.util.CommonUtilities;
import edu.kit.kastel.mcse.ardoco.core.common.util.DataRepositoryHelper;
import edu.kit.kastel.mcse.ardoco.core.execution.ArDoCo;
import edu.kit.kastel.mcse.ardoco.core.execution.runner.ArDoCoRunner;
import edu.kit.kastel.mcse.ardoco.tlr.codetraceability.SadSamCodeTraceabilityLinkRecovery;
import edu.kit.kastel.mcse.ardoco.tlr.codetraceability.SamCodeTraceabilityLinkRecovery;
import edu.kit.kastel.mcse.ardoco.core.common.util.CommonUtilities;
import edu.kit.kastel.mcse.ardoco.core.common.util.DataRepositoryHelper;
import edu.kit.kastel.mcse.ardoco.tlr.connectiongenerator.ConnectionGenerator;
import edu.kit.kastel.mcse.ardoco.core.execution.runner.ArDoCoRunner;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArCoTLModelProviderAgent;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArchitectureConfiguration;
import edu.kit.kastel.mcse.ardoco.tlr.recommendationgenerator.RecommendationGenerator;
import edu.kit.kastel.mcse.ardoco.tlr.text.providers.TextPreprocessingAgent;
import edu.kit.kastel.mcse.ardoco.tlr.textextraction.TextExtraction;
Expand Down Expand Up @@ -43,8 +44,11 @@ private void definePipeline(File inputText, File inputArchitectureModel, Archite

arDoCo.addPipelineStep(TextPreprocessingAgent.get(additionalConfigs, dataRepository));

ArCoTLModelProviderAgent arCoTLModelProviderAgent = ArCoTLModelProviderAgent.get(inputArchitectureModel, architectureModelType, inputCode,
additionalConfigs, dataRepository);
var architectureConfiguration = new ArchitectureConfiguration(inputArchitectureModel, architectureModelType);
var codeConfiguration = ArCoTLModelProviderAgent.getCodeConfiguration(inputCode);

ArCoTLModelProviderAgent arCoTLModelProviderAgent = ArCoTLModelProviderAgent.getArCoTLModelProviderAgent(dataRepository, additionalConfigs,
architectureConfiguration, codeConfiguration);
arDoCo.addPipelineStep(arCoTLModelProviderAgent);

arDoCo.addPipelineStep(TextExtraction.get(additionalConfigs, dataRepository));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import edu.kit.kastel.mcse.ardoco.core.api.models.ArchitectureModelType;
import edu.kit.kastel.mcse.ardoco.core.common.util.CommonUtilities;
import edu.kit.kastel.mcse.ardoco.core.common.util.DataRepositoryHelper;
import edu.kit.kastel.mcse.ardoco.tlr.connectiongenerator.ConnectionGenerator;
import edu.kit.kastel.mcse.ardoco.core.execution.runner.ArDoCoRunner;
import edu.kit.kastel.mcse.ardoco.tlr.connectiongenerator.ConnectionGenerator;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArCoTLModelProviderAgent;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArchitectureConfiguration;
import edu.kit.kastel.mcse.ardoco.tlr.recommendationgenerator.RecommendationGenerator;
import edu.kit.kastel.mcse.ardoco.tlr.text.providers.TextPreprocessingAgent;
import edu.kit.kastel.mcse.ardoco.tlr.textextraction.TextExtraction;
Expand Down Expand Up @@ -41,8 +42,10 @@ private void definePipeline(File inputText, File inputArchitectureModel, Archite
DataRepositoryHelper.putInputText(dataRepository, text);

this.getArDoCo().addPipelineStep(TextPreprocessingAgent.get(additionalConfigs, dataRepository));

var architectureConfiguration = new ArchitectureConfiguration(inputArchitectureModel, architectureModelType);
ArCoTLModelProviderAgent arCoTLModelProviderAgent = //
ArCoTLModelProviderAgent.get(inputArchitectureModel, architectureModelType, null, additionalConfigs, dataRepository);
ArCoTLModelProviderAgent.getArCoTLModelProviderAgent(dataRepository, additionalConfigs, architectureConfiguration, null);
this.getArDoCo().addPipelineStep(arCoTLModelProviderAgent);

this.getArDoCo().addPipelineStep(TextExtraction.get(additionalConfigs, dataRepository));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

import edu.kit.kastel.mcse.ardoco.core.api.models.ArchitectureModelType;
import edu.kit.kastel.mcse.ardoco.core.execution.ArDoCo;
import edu.kit.kastel.mcse.ardoco.tlr.codetraceability.SamCodeTraceabilityLinkRecovery;
import edu.kit.kastel.mcse.ardoco.core.execution.runner.ArDoCoRunner;
import edu.kit.kastel.mcse.ardoco.tlr.codetraceability.SamCodeTraceabilityLinkRecovery;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArCoTLModelProviderAgent;
import edu.kit.kastel.mcse.ardoco.tlr.models.agents.ArchitectureConfiguration;

public class ArDoCoForSamCodeTraceabilityLinkRecovery extends ArDoCoRunner {

Expand All @@ -28,8 +29,11 @@ private void definePipeline(File inputArchitectureModel, ArchitectureModelType a
ArDoCo arDoCo = this.getArDoCo();
var dataRepository = arDoCo.getDataRepository();

ArCoTLModelProviderAgent arCoTLModelProviderAgent = ArCoTLModelProviderAgent.get(inputArchitectureModel, architectureModelType, inputCode,
additionalConfigs, dataRepository);
var codeConfiguration = ArCoTLModelProviderAgent.getCodeConfiguration(inputCode);
var architectureConfiguration = new ArchitectureConfiguration(inputArchitectureModel, architectureModelType);

ArCoTLModelProviderAgent arCoTLModelProviderAgent = ArCoTLModelProviderAgent.getArCoTLModelProviderAgent(dataRepository, additionalConfigs,
architectureConfiguration, codeConfiguration);
arDoCo.addPipelineStep(arCoTLModelProviderAgent);
arDoCo.addPipelineStep(SamCodeTraceabilityLinkRecovery.get(additionalConfigs, dataRepository));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,13 @@
import java.util.List;
import java.util.SortedMap;

import edu.kit.kastel.mcse.ardoco.core.api.models.ArchitectureModelType;
import edu.kit.kastel.mcse.ardoco.core.api.models.arcotl.code.CodeItemRepository;
import org.slf4j.LoggerFactory;

import edu.kit.kastel.mcse.ardoco.core.data.DataRepository;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.Extractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.architecture.ArchitectureExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.architecture.pcm.PcmExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.architecture.uml.UmlExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.code.AllLanguagesExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.code.CodeExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.informants.ArCoTLModelProviderInformant;
import edu.kit.kastel.mcse.ardoco.core.pipeline.agent.Informant;
import edu.kit.kastel.mcse.ardoco.core.pipeline.agent.PipelineAgent;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.Extractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.informants.ArCoTLModelProviderInformant;

/**
* Agent that provides information from models.
Expand All @@ -27,42 +22,43 @@ public class ArCoTLModelProviderAgent extends PipelineAgent {
/**
* Instantiates a new model provider agent.
* The constructor takes a list of ModelConnectors that are executed and used to extract information from models.
* You can specify the extractors xor the code model file.
*
* @param data the DataRepository
* @param extractors the list of ModelConnectors that should be used
* @param data the DataRepository
* @param architectureConfiguration the architecture configuration
* @param codeConfiguration the code configuration
*/
public ArCoTLModelProviderAgent(DataRepository data, List<Extractor> extractors) {
super(informants(data, extractors), ArCoTLModelProviderAgent.class.getSimpleName(), data);
public ArCoTLModelProviderAgent(DataRepository data, ArchitectureConfiguration architectureConfiguration, CodeConfiguration codeConfiguration) {
super(informants(data, architectureConfiguration, codeConfiguration), ArCoTLModelProviderAgent.class.getSimpleName(), data);
}

private static List<? extends Informant> informants(DataRepository data, List<Extractor> extractors) {
return extractors.stream().map(e -> new ArCoTLModelProviderInformant(data, e)).toList();
}

public static ArCoTLModelProviderAgent get(File inputArchitectureModel, ArchitectureModelType architectureModelType, File inputCode,
SortedMap<String, String> additionalConfigs, DataRepository dataRepository) {

List<Extractor> extractors = new ArrayList<>();
private static List<? extends Informant> informants(DataRepository data, ArchitectureConfiguration architectureConfiguration,
CodeConfiguration codeConfiguration) {
List<Informant> informants = new ArrayList<>();
if (architectureConfiguration != null) {
informants.add(new ArCoTLModelProviderInformant(data, architectureConfiguration.extractor()));
}

if (inputArchitectureModel != null && architectureModelType != null) {
ArchitectureExtractor architectureExtractor = switch (architectureModelType) {
case PCM -> new PcmExtractor(inputArchitectureModel.getAbsolutePath());
case UML -> new UmlExtractor(inputArchitectureModel.getAbsolutePath());
};
extractors.add(architectureExtractor);
if (codeConfiguration != null && codeConfiguration.type() == CodeConfiguration.CodeConfigurationType.ACM_FILE) {
informants.add(new ArCoTLModelProviderInformant(data, codeConfiguration.code()));
}

if (inputCode != null) {
CodeItemRepository codeItemRepository = new CodeItemRepository();
CodeExtractor codeExtractor = new AllLanguagesExtractor(codeItemRepository, inputCode.getAbsolutePath());
extractors.add(codeExtractor);
if (codeConfiguration != null && codeConfiguration.type() == CodeConfiguration.CodeConfigurationType.DIRECTORY) {
for (Extractor e : codeConfiguration.extractors()) {
informants.add(new ArCoTLModelProviderInformant(data, e));
}
}

if (extractors.isEmpty()) {
throw new IllegalArgumentException("No model extractor was provided.");
return informants;
}

public static ArCoTLModelProviderAgent getArCoTLModelProviderAgent(DataRepository dataRepository, SortedMap<String, String> additionalConfigs,
ArchitectureConfiguration architectureConfiguration, CodeConfiguration codeConfiguration) {
if (architectureConfiguration == null && codeConfiguration == null) {
throw new IllegalArgumentException("At least one configuration must be provided");
}

ArCoTLModelProviderAgent agent = new ArCoTLModelProviderAgent(dataRepository, extractors);
var agent = new ArCoTLModelProviderAgent(dataRepository, architectureConfiguration, codeConfiguration);
agent.applyConfiguration(additionalConfigs);
return agent;
}
Expand All @@ -71,4 +67,24 @@ public static ArCoTLModelProviderAgent get(File inputArchitectureModel, Architec
protected void delegateApplyConfigurationToInternalObjects(SortedMap<String, String> additionalConfiguration) {
// empty
}

public static CodeConfiguration getCodeConfiguration(File inputCode) {
if (inputCode == null) {
throw new IllegalArgumentException("Code file must not be null");
}

if (inputCode.isFile()) {
return new CodeConfiguration(inputCode, CodeConfiguration.CodeConfigurationType.ACM_FILE);
}

// Legacy Support for only ACM_FILE in a directory
// TODO: Maybe delete in the future
if (inputCode.isDirectory() && new File(inputCode, "codeModel.acm").exists()) {
var logger = LoggerFactory.getLogger(ArCoTLModelProviderAgent.class);
logger.error("Legacy support for only ACM_FILE in a directory. Please use the ACM_FILE directly.");
return new CodeConfiguration(new File(inputCode, "codeModel.acm"), CodeConfiguration.CodeConfigurationType.ACM_FILE);
}

return new CodeConfiguration(inputCode, CodeConfiguration.CodeConfigurationType.DIRECTORY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* Licensed under MIT 2024. */
package edu.kit.kastel.mcse.ardoco.tlr.models.agents;

import java.io.File;

import edu.kit.kastel.mcse.ardoco.core.api.models.ArchitectureModelType;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.Extractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.architecture.pcm.PcmExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.architecture.uml.UmlExtractor;

public record ArchitectureConfiguration(File architectureFile, ArchitectureModelType type) {
public ArchitectureConfiguration {
if (architectureFile == null || type == null) {
throw new IllegalArgumentException("Architecture file and type must not be null");
}
if (!architectureFile.exists() || !architectureFile.isFile()) {
throw new IllegalArgumentException("Architecture file must exist and be a file");
}
}

public Extractor extractor() {
return switch (type) {
case PCM -> new PcmExtractor(architectureFile.getAbsolutePath());
case UML -> new UmlExtractor(architectureFile.getAbsolutePath());
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* Licensed under MIT 2024. */
package edu.kit.kastel.mcse.ardoco.tlr.models.agents;

import java.io.File;
import java.util.List;

import edu.kit.kastel.mcse.ardoco.core.api.models.arcotl.code.CodeItemRepository;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.Extractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.code.AllLanguagesExtractor;
import edu.kit.kastel.mcse.ardoco.tlr.models.connectors.generators.code.CodeExtractor;

public record CodeConfiguration(File code, CodeConfigurationType type) {

public CodeConfiguration {
if (code == null || type == null) {
throw new IllegalArgumentException("Code file and type must not be null");
}

if (!code.exists()) {
throw new IllegalArgumentException("Code file must exist");
}

if (type == CodeConfigurationType.DIRECTORY && code.isFile()) {
throw new IllegalArgumentException("Code file must be a directory in DIRECTORY mode");
}

if (type == CodeConfigurationType.ACM_FILE && !code.isFile()) {
throw new IllegalArgumentException("Code file must be a file in ACM_FILE mode");
}
}

public List<Extractor> extractors() {
if (type == CodeConfigurationType.DIRECTORY) {
CodeItemRepository codeItemRepository = new CodeItemRepository();
CodeExtractor codeExtractor = new AllLanguagesExtractor(codeItemRepository, code.getAbsolutePath());
return List.of(codeExtractor);
}
throw new IllegalStateException("CodeConfigurationType not supported");
}

public enum CodeConfigurationType {
DIRECTORY, ACM_FILE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,6 @@ public void writeOutCodeModel(CodeModel codeModel) {
writeOutCodeModel(codeModel, file);
}

public CodeModel readInCodeModel() {
File codeModelFile = new File(this.getCodeModelFileString());
return readInCodeModel(codeModelFile);
}

public static CodeModel readInCodeModel(File codeModelFile) {
if (codeModelFile != null && codeModelFile.isFile()) {
logger.info("Reading in existing code model.");
Expand Down
Loading

0 comments on commit c9c763e

Please sign in to comment.