CatalogFacade.java
package com.taxonomy.catalog.service;
import com.taxonomy.catalog.model.TaxonomyNode;
import com.taxonomy.dto.ArchiMateImportResult;
import com.taxonomy.dto.TaxonomyNodeDto;
import com.taxonomy.dto.TaxonomyRelationDto;
import com.taxonomy.workspace.service.WorkspaceContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.InputStream;
import java.util.List;
/** High-level catalog use-case facade with explicit workspace scope. */
@Service
public class CatalogFacade {
private static final Logger log = LoggerFactory.getLogger(CatalogFacade.class);
private final TaxonomyService taxonomyService;
private final TaxonomyRelationService relationService;
private final ArchiMateXmlImporter archiMateXmlImporter;
private final SearchService searchService;
public CatalogFacade(TaxonomyService taxonomyService,
TaxonomyRelationService relationService,
ArchiMateXmlImporter archiMateXmlImporter,
SearchService searchService) {
this.taxonomyService = taxonomyService;
this.relationService = relationService;
this.archiMateXmlImporter = archiMateXmlImporter;
this.searchService = searchService;
}
@Transactional(readOnly = true)
public TaxonomyNodeDto getTreeWithRelations(String rootCode, WorkspaceContext workspaceContext) {
TaxonomyNode node = taxonomyService.getNodeByCode(rootCode);
if (node == null) {
log.debug("No taxonomy node found for code '{}'", rootCode);
return null;
}
TaxonomyNodeDto dto = taxonomyService.toDto(node);
attachRelations(dto, workspaceContext);
return dto;
}
public ArchiMateImportResult importAndValidate(InputStream xmlStream,
WorkspaceContext workspaceContext) {
if (workspaceContext == null) {
throw new IllegalArgumentException("Workspace context is required for ArchiMate import");
}
log.info("Starting ArchiMate XML import via facade for workspace {}",
workspaceContext.workspaceId());
ArchiMateImportResult result = archiMateXmlImporter.importXml(xmlStream, workspaceContext);
log.info("ArchiMate import complete – {} elements matched, {} relations created",
result.getElementsMatched(), result.getRelationsImported());
return result;
}
@Transactional(readOnly = true)
public List<TaxonomyNodeDto> searchWithContext(String query,
int maxResults,
WorkspaceContext workspaceContext) {
List<TaxonomyNodeDto> results = searchService.search(query, maxResults);
results.forEach(dto -> attachRelations(dto, workspaceContext));
return results;
}
private void attachRelations(TaxonomyNodeDto dto, WorkspaceContext workspaceContext) {
WorkspaceContext context = workspaceContext != null ? workspaceContext : WorkspaceContext.SHARED;
List<TaxonomyRelationDto> relations =
relationService.getRelationsForNode(dto.getCode(), context.workspaceId());
dto.setOutgoingRelations(relations.stream()
.filter(relation -> dto.getCode().equals(relation.getSourceCode()))
.toList());
dto.setIncomingRelations(relations.stream()
.filter(relation -> dto.getCode().equals(relation.getTargetCode()))
.toList());
}
}