Skip to content

Commit 828688a

Browse files
committed
Sync from monorepo - main
1 parent f02c401 commit 828688a

File tree

4 files changed

+817
-0
lines changed

4 files changed

+817
-0
lines changed
Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
/* Licensed under MIT 2022-2026. */
2+
package edu.kit.kastel.mcse.ardoco.core.api.output;
3+
4+
import java.util.Comparator;
5+
import java.util.LinkedHashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
import org.eclipse.collections.api.factory.Lists;
10+
import org.eclipse.collections.api.factory.Sets;
11+
import org.eclipse.collections.api.list.ImmutableList;
12+
import org.eclipse.collections.api.list.MutableList;
13+
import org.eclipse.collections.api.set.ImmutableSet;
14+
import org.eclipse.collections.api.set.MutableSet;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
import edu.kit.kastel.mcse.ardoco.core.api.PreprocessingData;
19+
import edu.kit.kastel.mcse.ardoco.core.api.SimplePreprocessingData;
20+
import edu.kit.kastel.mcse.ardoco.core.api.entity.ArchitectureEntity;
21+
import edu.kit.kastel.mcse.ardoco.core.api.entity.ModelEntity;
22+
import edu.kit.kastel.mcse.ardoco.core.api.models.Metamodel;
23+
import edu.kit.kastel.mcse.ardoco.core.api.models.Model;
24+
import edu.kit.kastel.mcse.ardoco.core.api.models.ModelStates;
25+
import edu.kit.kastel.mcse.ardoco.core.api.stage.codetraceability.CodeTraceabilityState;
26+
import edu.kit.kastel.mcse.ardoco.core.api.stage.connectiongenerator.ConnectionState;
27+
import edu.kit.kastel.mcse.ardoco.core.api.stage.connectiongenerator.ner.NerConnectionState;
28+
import edu.kit.kastel.mcse.ardoco.core.api.stage.inconsistency.Inconsistency;
29+
import edu.kit.kastel.mcse.ardoco.core.api.stage.inconsistency.InconsistencyState;
30+
import edu.kit.kastel.mcse.ardoco.core.api.stage.inconsistency.InconsistentSentence;
31+
import edu.kit.kastel.mcse.ardoco.core.api.stage.inconsistency.ModelInconsistency;
32+
import edu.kit.kastel.mcse.ardoco.core.api.stage.inconsistency.TextInconsistency;
33+
import edu.kit.kastel.mcse.ardoco.core.api.text.Sentence;
34+
import edu.kit.kastel.mcse.ardoco.core.api.text.SentenceEntity;
35+
import edu.kit.kastel.mcse.ardoco.core.api.text.Text;
36+
import edu.kit.kastel.mcse.ardoco.core.api.tracelink.TraceLink;
37+
import edu.kit.kastel.mcse.ardoco.core.architecture.Deterministic;
38+
import edu.kit.kastel.mcse.ardoco.core.common.util.DataRepositoryHelper;
39+
import edu.kit.kastel.mcse.ardoco.core.data.DataRepository;
40+
41+
/**
42+
* This record represents the result of running ARDoCo. It is backed by a {@link DataRepository} and provides access to data from it. Besides accessing all data
43+
* from the calculation steps, this record also provides convenience methods to directly access results such as found trace links and detected inconsistencies.
44+
*/
45+
@Deterministic
46+
public record ArdocoResult(DataRepository dataRepository) {
47+
private static final Logger logger = LoggerFactory.getLogger(ArdocoResult.class);
48+
49+
private static String formatTraceLinksHumanReadable(TraceLink<SentenceEntity, ModelEntity> traceLink) {
50+
String modelElementName = traceLink.getSecondEndpoint().getName();
51+
String modelElementUid = traceLink.getSecondEndpoint().getId();
52+
String modelInfo = String.format("%s (%s)", modelElementName, modelElementUid);
53+
54+
var sentence = traceLink.getFirstEndpoint().getSentence();
55+
int sentenceNumber = sentence.getSentenceNumber() + 1;
56+
String sentenceInfo = String.format("S%3d: \"%s\"", sentenceNumber, sentence.getText());
57+
58+
return String.format("%-42s <--> %s", modelInfo, sentenceInfo);
59+
}
60+
61+
/**
62+
* Returns the name of the project the results are based on.
63+
*
64+
* @return the name of the project the results are based on
65+
*/
66+
public String getProjectName() {
67+
return DataRepositoryHelper.getProjectPipelineData(this.dataRepository).getProjectName();
68+
}
69+
70+
/**
71+
* Returns the set of {@link TraceLink TraceLinks} that were found for the model with the given metamodel.
72+
*
73+
* @param metamodel the metamodel to get trace links for
74+
* @return {@link TraceLink TraceLinks} for the model with the given metamodel
75+
*/
76+
public ImmutableSet<TraceLink<SentenceEntity, ModelEntity>> getTraceLinksForModel(Metamodel metamodel) {
77+
ConnectionState connectionState = this.getConnectionState(metamodel);
78+
if (connectionState != null) {
79+
return connectionState.getTraceLinks();
80+
}
81+
return Sets.immutable.empty();
82+
}
83+
84+
/**
85+
* Returns the set of {@link TraceLink TraceLinks} for architecture models.
86+
*
87+
* @return set of {@link TraceLink TraceLinks} for architecture models
88+
*/
89+
public ImmutableList<TraceLink<SentenceEntity, ModelEntity>> getArchitectureTraceLinks() {
90+
MutableSet<TraceLink<SentenceEntity, ModelEntity>> traceLinks = Sets.mutable.empty();
91+
92+
for (var metamodel : this.getMetamodels()) {
93+
if (metamodel.isArchitectureModel()) {
94+
traceLinks.addAll(this.getTraceLinksForModel(metamodel).castToCollection());
95+
}
96+
}
97+
return traceLinks.toImmutableList();
98+
}
99+
100+
/**
101+
* Returns the set of {@link TraceLink TraceLinks} for architecture models as formatted strings. The strings are formatted to be human-readable.
102+
*
103+
* @return trace links as formatted strings
104+
*/
105+
public List<String> getAllTraceLinksAsBeautifiedStrings() {
106+
return this.getArchitectureTraceLinks()
107+
.toSortedList(Comparator.comparingInt(tl -> tl.getFirstEndpoint().getSentence().getSentenceNumber()))
108+
.collect(ArdocoResult::formatTraceLinksHumanReadable);
109+
}
110+
111+
/**
112+
* Returns the list of {@link TraceLink TraceLinks} between architecture entities and code entities. If there are none, it returns an empty list.
113+
*
114+
* @return the list of {@link TraceLink TraceLinks} between architecture and code entities
115+
*/
116+
public ImmutableList<TraceLink<? extends ArchitectureEntity, ? extends ModelEntity>> getSamCodeTraceLinks() {
117+
var samCodeTraceabilityState = this.getCodeTraceabilityState();
118+
if (samCodeTraceabilityState != null) {
119+
return Lists.immutable.withAll(samCodeTraceabilityState.getSamCodeTraceLinks());
120+
}
121+
return Lists.immutable.empty();
122+
}
123+
124+
/**
125+
* Returns the list of {@link TraceLink TraceLinks} between sentences and code entities. If there are none, it returns an empty list.
126+
*
127+
* @return the list of {@link TraceLink TraceLinks} between sentences and code entities
128+
*/
129+
public ImmutableList<TraceLink<SentenceEntity, ? extends ModelEntity>> getSadCodeTraceLinks() {
130+
var samCodeTraceabilityState = this.getCodeTraceabilityState();
131+
if (samCodeTraceabilityState != null) {
132+
return Lists.immutable.withAll(samCodeTraceabilityState.getSadCodeTraceLinks());
133+
}
134+
return Lists.immutable.empty();
135+
}
136+
137+
/**
138+
* Returns all {@link Inconsistency inconsistencies} that were found for the model with the given metamodel.
139+
*
140+
* @param metamodel the metamodel to get inconsistencies for
141+
* @return inconsistencies for the model
142+
*/
143+
public ImmutableList<Inconsistency> getAllInconsistenciesForModel(Metamodel metamodel) {
144+
InconsistencyState inconsistencyState = this.getInconsistencyState(metamodel);
145+
if (inconsistencyState != null) {
146+
return inconsistencyState.getInconsistencies();
147+
}
148+
return Lists.immutable.empty();
149+
}
150+
151+
/**
152+
* Returns a list of {@link Inconsistency inconsistencies} that were found for the model with the given metamodel and that are of the specified
153+
* inconsistency class.
154+
*
155+
* @param metamodel the metamodel to get inconsistencies for
156+
* @param inconsistencyType the type of inconsistency to filter for
157+
* @return inconsistencies for the model with the given type
158+
*/
159+
public <T extends Inconsistency> ImmutableList<T> getInconsistenciesOfTypeForModel(Metamodel metamodel, Class<T> inconsistencyType) {
160+
return this.getAllInconsistenciesForModel(metamodel).select(i -> inconsistencyType.isAssignableFrom(i.getClass())).collect(inconsistencyType::cast);
161+
}
162+
163+
/**
164+
* Returns a list of all {@link Inconsistency inconsistencies} that were found.
165+
*
166+
* @return all found inconsistencies
167+
*/
168+
public ImmutableList<Inconsistency> getAllInconsistencies() {
169+
MutableList<Inconsistency> inconsistencies = Lists.mutable.empty();
170+
for (var model : this.getMetamodels()) {
171+
inconsistencies.addAll(this.getAllInconsistenciesForModel(model).castToCollection());
172+
}
173+
return inconsistencies.toImmutable();
174+
}
175+
176+
/**
177+
* Returns all {@link TextInconsistency TextInconsistencies} that were found.
178+
*
179+
* @return all found TextInconsistencies
180+
*/
181+
public ImmutableList<TextInconsistency> getAllTextInconsistencies() {
182+
var inconsistencies = this.getAllInconsistencies();
183+
return inconsistencies.select(i -> TextInconsistency.class.isAssignableFrom(i.getClass())).collect(TextInconsistency.class::cast);
184+
}
185+
186+
/**
187+
* Returns all {@link ModelInconsistency ModelInconsistencies} that were found.
188+
*
189+
* @return all found ModelInconsistencies
190+
*/
191+
public ImmutableList<ModelInconsistency> getAllModelInconsistencies() {
192+
var inconsistencies = this.getAllInconsistencies();
193+
return inconsistencies.select(i -> ModelInconsistency.class.isAssignableFrom(i.getClass())).collect(ModelInconsistency.class::cast);
194+
}
195+
196+
/**
197+
* Returns a list of {@link InconsistentSentence InconsistentSentences}.
198+
*
199+
* @return all InconsistentSentences
200+
*/
201+
public ImmutableList<InconsistentSentence> getInconsistentSentences() {
202+
Map<Integer, InconsistentSentence> incSentenceMap = new LinkedHashMap<>();
203+
204+
var inconsistencies = this.getAllTextInconsistencies();
205+
for (var inconsistency : inconsistencies) {
206+
int sentenceNo = inconsistency.getSentenceNumber();
207+
var incSentence = incSentenceMap.get(sentenceNo);
208+
if (incSentence != null) {
209+
incSentence.addInconsistency(inconsistency);
210+
} else {
211+
var sentence = this.getSentence(sentenceNo);
212+
incSentence = new InconsistentSentence(sentence, inconsistency);
213+
incSentenceMap.put(sentenceNo, incSentence);
214+
}
215+
}
216+
217+
var sortedInconsistentSentences = Lists.mutable.withAll(incSentenceMap.values()).sortThisByInt(i -> i.sentence().getSentenceNumber() + 1);
218+
return sortedInconsistentSentences.toImmutable();
219+
}
220+
221+
/**
222+
* Returns the {@link Sentence} with the given sentence number.
223+
*
224+
* @param sentenceNo the sentence number
225+
* @return sentence with the given number
226+
*/
227+
private Sentence getSentence(int sentenceNo) {
228+
return this.getText().getSentences().detect(s -> s.getSentenceNumber() + 1 == sentenceNo);
229+
}
230+
231+
/**
232+
* Returns the internal {@link ConnectionState} for the model with the given metamodel or null if there is none.
233+
*
234+
* @param metamodel the metamodel to get the connection state for
235+
* @return the connection state or null if there is no {@link ConnectionState} for the given metamodel
236+
*/
237+
public ConnectionState getConnectionState(Metamodel metamodel) {
238+
if (DataRepositoryHelper.hasConnectionStates(this.dataRepository)) {
239+
var connectionStates = DataRepositoryHelper.getConnectionStates(this.dataRepository);
240+
return connectionStates.getConnectionState(metamodel);
241+
}
242+
logger.warn("No ConnectionState found.");
243+
return null;
244+
}
245+
246+
/**
247+
* Returns the internal {@link NerConnectionState} for the model with the given metamodel or null if there is none.
248+
*
249+
* @param metamodel the metamodel to get the connection state for
250+
* @return the connection state or null if there is no {@link ConnectionState} for the given metamodel
251+
*/
252+
public NerConnectionState getNerConnectionState(Metamodel metamodel) {
253+
if (DataRepositoryHelper.hasNerConnectionStates(this.dataRepository)) {
254+
var connectionStates = DataRepositoryHelper.getNerConnectionStates(this.dataRepository);
255+
return connectionStates.getNerConnectionState(metamodel);
256+
}
257+
logger.warn("No NerConnectionState found.");
258+
return null;
259+
}
260+
261+
/**
262+
* Returns the internal {@link InconsistencyState} for the model with the given metamodel or null if there is none.
263+
*
264+
* @param metamodel the metamodel to get the inconsistency state for
265+
* @return the inconsistency state or null if there is no {@link InconsistencyState} for the given metamodel
266+
*/
267+
public InconsistencyState getInconsistencyState(Metamodel metamodel) {
268+
if (DataRepositoryHelper.hasInconsistencyStates(this.dataRepository)) {
269+
var inconsistencyStates = DataRepositoryHelper.getInconsistencyStates(this.dataRepository);
270+
return inconsistencyStates.getInconsistencyState(metamodel);
271+
}
272+
logger.warn("No InconsistencyState found.");
273+
return null;
274+
}
275+
276+
/**
277+
* Returns the internal {@link CodeTraceabilityState} or null if there is none.
278+
*
279+
* @return the {@link CodeTraceabilityState} or null if there is no {@link CodeTraceabilityState}
280+
*/
281+
public CodeTraceabilityState getCodeTraceabilityState() {
282+
if (DataRepositoryHelper.hasCodeTraceabilityState(this.dataRepository)) {
283+
return DataRepositoryHelper.getCodeTraceabilityState(this.dataRepository);
284+
}
285+
logger.warn("No SamCodeTraceabilityState found.");
286+
return null;
287+
}
288+
289+
/**
290+
* Returns the internal {@link ModelStates}.
291+
*
292+
* @return the ModelStates
293+
*/
294+
private ModelStates getModelStates() {
295+
return DataRepositoryHelper.getModelStatesData(this.dataRepository);
296+
}
297+
298+
/**
299+
* Returns a list of all metamodels for all the models that were loaded.
300+
*
301+
* @return list of all metamodels
302+
*/
303+
public List<Metamodel> getMetamodels() {
304+
ModelStates modelStates = this.getModelStates();
305+
return Lists.mutable.ofAll(modelStates.getMetamodels());
306+
}
307+
308+
/**
309+
* Returns the internal {@link Model} for the model with the given metamodel.
310+
*
311+
* @param metamodel the metamodel to get the model for
312+
* @return the Model
313+
*/
314+
public Model getModelState(Metamodel metamodel) {
315+
ModelStates modelStates = this.getModelStates();
316+
return modelStates.getModel(metamodel);
317+
}
318+
319+
/**
320+
* Returns the internal {@link PreprocessingData}.
321+
*
322+
* @return the preprocessing data
323+
*/
324+
public PreprocessingData getPreprocessingData() {
325+
return this.dataRepository.getData(PreprocessingData.ID, PreprocessingData.class).orElseThrow();
326+
}
327+
328+
/**
329+
* Returns the internal {@link SimplePreprocessingData}.
330+
*
331+
* @return the preprocessing data
332+
*/
333+
public SimplePreprocessingData getSimplePreprocessingData() {
334+
return this.dataRepository.getData(SimplePreprocessingData.ID, SimplePreprocessingData.class).orElseThrow();
335+
}
336+
337+
/**
338+
* Returns the {@link Text}.
339+
*
340+
* @return the Text
341+
*/
342+
public Text getText() {
343+
var preprocessingData = this.getPreprocessingData();
344+
return preprocessingData.getText();
345+
}
346+
}

0 commit comments

Comments
 (0)