ImportApiController.java
package com.taxonomy.catalog.controller;
import com.taxonomy.dto.FrameworkImportResult;
import com.taxonomy.dto.ProfileInfo;
import com.taxonomy.versioning.service.RepositoryStateService;
import com.taxonomy.workspace.service.WorkspaceResolver;
import com.taxonomy.catalog.service.importer.FrameworkImportService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* REST API for generic framework import.
*
* <p>Endpoints:
* <ul>
* <li>{@code GET /api/import/profiles} — List available import profiles</li>
* <li>{@code POST /api/import/preview/{profileId}} — Dry-run import with statistics</li>
* <li>{@code POST /api/import/{profileId}} — Full import into database</li>
* </ul>
*/
@RestController
@RequestMapping("/api/import")
@Tag(name = "Framework Import")
public class ImportApiController {
private static final Logger log = LoggerFactory.getLogger(ImportApiController.class);
private final FrameworkImportService importService;
private final RepositoryStateService repositoryStateService;
private final WorkspaceResolver workspaceResolver;
public ImportApiController(FrameworkImportService importService,
RepositoryStateService repositoryStateService,
WorkspaceResolver workspaceResolver) {
this.importService = importService;
this.repositoryStateService = repositoryStateService;
this.workspaceResolver = workspaceResolver;
}
/**
* Returns all available import profiles with their supported types and file formats.
*/
@Operation(summary = "List import profiles",
description = "Returns all registered import profiles (UAF, APQC, C4, etc.)")
@GetMapping("/profiles")
public ResponseEntity<List<ProfileInfo>> listProfiles() {
return ResponseEntity.ok(importService.getAvailableProfiles());
}
/**
* Dry-run: parses and maps the uploaded file but does not write to the database.
*/
@Operation(summary = "Preview import",
description = "Parse and map the file without writing to the database. Returns mapping statistics.")
@PostMapping(value = "/preview/{profileId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<FrameworkImportResult> preview(
@PathVariable String profileId,
@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().build();
}
try {
FrameworkImportResult result = importService.preview(profileId, file.getInputStream());
return ResponseEntity.ok(result);
} catch (Exception e) {
log.error("Preview failed for profile {} with file {}", profileId, file.getOriginalFilename(), e);
return ResponseEntity.badRequest().build();
}
}
/**
* Full import: parses, maps, serializes to DSL, and materializes into the database.
*/
@Operation(summary = "Import framework model",
description = "Parse, map, and materialize the file into the database")
@PostMapping(value = "/{profileId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Map<String, Object>> importFile(
@PathVariable String profileId,
@RequestParam("file") MultipartFile file,
@RequestParam(value = "branch", required = false, defaultValue = "main") String branch) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().build();
}
try {
FrameworkImportResult result = importService.importFile(profileId, file.getInputStream(), branch);
Map<String, Object> response = new LinkedHashMap<>();
response.put("result", result);
response.put("viewContext", repositoryStateService.getViewContext(
workspaceResolver.resolveCurrentUsername(), branch));
return ResponseEntity.ok(response);
} catch (Exception e) {
log.error("Import failed for profile {} with file {}", profileId, file.getOriginalFilename(), e);
return ResponseEntity.badRequest().build();
}
}
}