ExternalModelMapper.java
package com.taxonomy.dsl.mapping;
import com.taxonomy.dsl.model.ArchitectureElement;
import com.taxonomy.dsl.model.ArchitectureRelation;
import com.taxonomy.dsl.model.CanonicalArchitectureModel;
import com.taxonomy.dsl.model.TaxonomyRootTypes;
import java.util.*;
/**
* Generic converter that transforms external framework data into a
* {@link CanonicalArchitectureModel} using a {@link MappingProfile}.
*
* <p>For every element and relation the profile is consulted to translate the
* external type to a canonical type and to enrich the result with
* framework-specific extension properties (prefixed with {@code x-}).
*/
public class ExternalModelMapper {
private final MappingProfile profile;
public ExternalModelMapper(MappingProfile profile) {
Objects.requireNonNull(profile, "profile must not be null");
this.profile = profile;
}
/**
* Map a list of external elements and relations to a canonical architecture model.
*
* @param elements external elements to map
* @param relations external relations to map
* @return a {@link MappingResult} containing the model, warnings, and statistics
*/
public MappingResult map(List<ExternalElement> elements, List<ExternalRelation> relations) {
CanonicalArchitectureModel model = new CanonicalArchitectureModel();
List<String> warnings = new ArrayList<>();
Set<String> unmappedTypes = new LinkedHashSet<>();
int mappedElements = 0;
int mappedRelations = 0;
// Map elements
for (ExternalElement ext : elements) {
String rootCode = profile.mapElementType(ext.type());
if (rootCode == null) {
unmappedTypes.add(ext.type());
warnings.add("Unmapped element type: " + ext.type() + " (element " + ext.name() + ")");
// Still create an element, but mark it as unmapped
ArchitectureElement el = createUnmappedElement(ext);
model.getElements().add(el);
continue;
}
String dslType = TaxonomyRootTypes.typeFor(rootCode);
ArchitectureElement el = new ArchitectureElement();
el.setId(ext.id());
el.setType(dslType);
el.setTitle(ext.name());
el.setDescription(ext.description());
// Set extensions: source framework marker + profile-specific extensions
Map<String, String> extensions = new LinkedHashMap<>();
extensions.put("x-source-framework", profile.profileId());
Map<String, String> profileExtensions = profile.elementExtensions(
ext.type(), ext.properties() != null ? ext.properties() : Map.of());
extensions.putAll(profileExtensions);
el.setExtensions(extensions);
model.getElements().add(el);
mappedElements++;
}
// Map relations
for (ExternalRelation ext : relations) {
String relType = profile.mapRelationType(ext.type());
if (relType == null) {
unmappedTypes.add(ext.type());
warnings.add("Unmapped relation type: " + ext.type());
// Still create the relation with RELATED_TO as fallback
relType = "RELATED_TO";
} else {
mappedRelations++;
}
ArchitectureRelation rel = new ArchitectureRelation();
rel.setSourceId(ext.sourceId());
rel.setRelationType(relType);
rel.setTargetId(ext.targetId());
rel.setStatus("proposed");
rel.setProvenance(profile.profileId() + "-import");
// Set extensions
Map<String, String> extensions = new LinkedHashMap<>();
extensions.put("x-source-framework", profile.profileId());
Map<String, String> profileExtensions = profile.relationExtensions(
ext.type(), ext.properties() != null ? ext.properties() : Map.of());
extensions.putAll(profileExtensions);
rel.setExtensions(extensions);
model.getRelations().add(rel);
}
Map<String, Integer> stats = new LinkedHashMap<>();
stats.put("elements", elements.size());
stats.put("relations", relations.size());
stats.put("mappedElements", mappedElements);
stats.put("mappedRelations", mappedRelations);
stats.put("unmapped", unmappedTypes.size());
return new MappingResult(model, warnings, new ArrayList<>(unmappedTypes), stats);
}
private ArchitectureElement createUnmappedElement(ExternalElement ext) {
ArchitectureElement el = new ArchitectureElement();
el.setId(ext.id());
el.setType("Unknown");
el.setTitle(ext.name());
el.setDescription(ext.description());
Map<String, String> extensions = new LinkedHashMap<>();
extensions.put("x-source-framework", profile.profileId());
extensions.put("x-unmapped-type", ext.type());
el.setExtensions(extensions);
return el;
}
}