From c164ff78020c48d93f63bb13bec0647c8fa6faf2 Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Thu, 2 Oct 2025 15:37:04 +0200 Subject: [PATCH] retrieving apicurio artifacts with versions and references --- .../trask/apioperator/impl/ExportToWso2.java | 273 +----------------- 1 file changed, 14 insertions(+), 259 deletions(-) diff --git a/src/main/java/cz/trask/apioperator/impl/ExportToWso2.java b/src/main/java/cz/trask/apioperator/impl/ExportToWso2.java index d585aef..a82db76 100644 --- a/src/main/java/cz/trask/apioperator/impl/ExportToWso2.java +++ b/src/main/java/cz/trask/apioperator/impl/ExportToWso2.java @@ -1,12 +1,6 @@ package cz.trask.apioperator.impl; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -16,28 +10,17 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; import cz.trask.apioperator.AbstractProcess; -import cz.trask.apioperator.model.APIInfo; -import cz.trask.apioperator.model.APIList; -import cz.trask.apioperator.model.FileType; -import cz.trask.apioperator.model.HttpResponse; import cz.trask.apioperator.model.RegisterResponse; import cz.trask.apioperator.model.TokenResponse; -import cz.trask.apioperator.model.ZipEntryData; -import cz.trask.apioperator.utils.ZipExtractor; import io.apicurio.registry.rest.client.RegistryClient; import io.apicurio.registry.rest.client.RegistryClientFactory; -import io.apicurio.registry.rest.client.exception.VersionAlreadyExistsException; -import io.apicurio.registry.rest.v2.beans.ArtifactMetaData; import io.apicurio.registry.rest.v2.beans.ArtifactReference; -import io.apicurio.registry.rest.v2.beans.EditableMetaData; -import io.apicurio.registry.rest.v2.beans.Rule; +import io.apicurio.registry.rest.v2.beans.ArtifactSearchResults; +import io.apicurio.registry.rest.v2.beans.SearchedArtifact; +import io.apicurio.registry.rest.v2.beans.SearchedVersion; import io.apicurio.registry.rest.v2.beans.VersionSearchResults; -import io.apicurio.registry.types.RuleType; public class ExportToWso2 extends AbstractProcess { @@ -78,18 +61,15 @@ public class ExportToWso2 extends AbstractProcess { log.debug("Access token received – {}", token.getAccess_token()); - APIList apis = getList(config.getSourcePublisherApiUrl(), token); - if (apis == null || apis.getList() == null || apis.getList().length == 0) { - throw new IllegalStateException( - "No APIs to export that match your criteria! Check the name of the API you want to export."); - } + ArtifactSearchResults apis = client.searchArtifacts(config.getDefaultApiGroup(), null, null, null, null, + null, null, null, null); log.info("Found {} APIs", apis.getCount()); int maxThreads = config.getMaxThreads(); ExecutorService executor = Executors.newFixedThreadPool(maxThreads); - for (APIInfo api : apis.getList()) { + for (SearchedArtifact api : apis.getArtifacts()) { final int index = apiCounter.getAndIncrement(); executor.submit(() -> processApi(api, token, index, apis.getCount())); } @@ -105,138 +85,24 @@ public class ExportToWso2 extends AbstractProcess { } } - /** - * Process a single API – fetches the data, creates or updates the corresponding - * artifact in Apicurio. - */ - private void processApi(APIInfo api, TokenResponse tokenResponse, int index, int total) { + private void processApi(SearchedArtifact api, TokenResponse tokenResponse, int index, int total) { long start = System.currentTimeMillis(); - String status = api.getLifeCycleStatus(); - - if (!status.contains("PUBLISHED") && !status.contains("DEPRECATED")) { - log.info("Skipping API {} of {} – not published (ID={})", index, total, api.getId()); - return; - } try { log.info("Processing API {} of {}", index, total); - - Map httpHeaders = Collections.singletonMap("Authorization", - "Bearer " + tokenResponse.getAccess_token()); - - // 1) Retrieve basic information - HttpResponse apiInfoResp = makeRequest("GET", config.getSourceDevportalApiUrl() + "/apis/" + api.getId(), - httpHeaders, Collections.emptyMap()); - - HttpResponse subsResp = makeRequest("GET", - config.getSourcePublisherApiUrl() + "/subscriptions?apiId=" + api.getId(), httpHeaders, - Collections.emptyMap()); - - // 2) Export the API as a zip - HttpResponse exportedZip = makeRequest("GET", - config.getSourcePublisherApiUrl() + "/apis/export?apiId=" + api.getId(), httpHeaders, - Collections.emptyMap(), true); - - List zipEntries = ZipExtractor.extractFilesFromZip(exportedZip.getResponseBytes()); - String swagger = null; + VersionSearchResults versions = client.listArtifactVersions(config.getDefaultApiGroup(), api.getId(), null, null); - for (ZipEntryData e : zipEntries) { - if (e.getType().toString().equals(FileType.OPENAPI.toString())) { - log.debug("Found main API definition file: {}", e.getName()); - swagger = new String(e.getContent()); - break; + for (SearchedVersion ver : versions.getVersions()) { + log.info(" - Found version: {}", ver.getVersion()); + List ref = client.getArtifactReferencesByCoordinates(config.getDefaultApiGroup(), api.getId(), ver.getVersion()); + if (ref != null && !ref.isEmpty()) { + log.info("Artifact has {} references", ref.size()); } } - // 3) Deserialize JSON responses - TypeToken> mapType = new TypeToken<>() { - }; - Map apiMap = gson.fromJson(apiInfoResp.getResponse(), mapType.getType()); - Map subsMap = gson.fromJson(subsResp.getResponse(), mapType.getType()); - - @SuppressWarnings("unchecked") - List tagsList = (List) apiMap.get("tags"); - - // 4) Build the properties map - Map props = new LinkedHashMap<>(); - props.put("version", api.getVersion()); - props.put("status", status); - addSubscriptionsToProps(props, subsMap); - addEndpointsToProps(props, apiMap); - addTagsToProps(props, tagsList); - - // 5) Build the description that contains the publisher & devportal URLs - String baseDesc = api.getDescription() != null ? api.getDescription() : ""; - String pubUrl = config.getPublisherUrlPattern().replace("{API_ID}", api.getId()); - String devPortUrl = config.getDevportalUrlPattern().replace("{API_ID}", api.getId()); - - String fullDesc = baseDesc + " ***** PUBLISHER URL ***** " + pubUrl + " ***** DEVPORTAL URL ***** " - + devPortUrl; - - // 6) Update the swagger with the description and servers - Map swaggerMap = yaml.load(swagger); - JsonObject swaggerObj = gson.toJsonTree(swaggerMap).getAsJsonObject(); - updateSwagger(swaggerObj, apiMap, fullDesc); - - // 7) Prepare artifact creation/update - String group = config.getDefaultApiGroup(); - String mainArtifactId = api.getName() + api.getContext(); - - VersionSearchResults existingArtifacts; - try { - existingArtifacts = client.listArtifactVersions(group, mainArtifactId, 0, Integer.MAX_VALUE); - } catch (Exception e) { - log.debug("No API {} exists – will create it", api.getContext()); - existingArtifacts = null; - } - - if (existingArtifacts == null) { - // Create new artifact - List references = createReferencesFromZip(zipEntries, group, api); - - ArtifactMetaData meta = client.createArtifact(group, mainArtifactId, api.getVersion(), null, null, null, - api.getName(), fullDesc, null, null, null, - new ByteArrayInputStream(swaggerObj.toString().getBytes()), references); - - setMetaAndRules(meta, props, tagsList); - // Create the three required rules - createRule(meta, "NONE", RuleType.COMPATIBILITY); - createRule(meta, "NONE", RuleType.VALIDITY); - createRule(meta, "NONE", RuleType.INTEGRITY); - - } else { - // Artifact exists – check if the version exists - boolean versionExists = false; - try { - client.getArtifactVersionMetaData(group, mainArtifactId, api.getVersion()); - versionExists = true; - } catch (Exception e) { - // Version missing – will create it below - } - - List references = createReferencesFromZip(zipEntries, group, api); - - if (!versionExists) { - ArtifactMetaData meta = client.updateArtifact(group, mainArtifactId, api.getVersion(), - api.getName(), fullDesc, new ByteArrayInputStream(swaggerObj.toString().getBytes()), - references); - setMetaAndRules(meta, props, tagsList); - } else { - // Version already exists – no action needed - log.warn("API {} with version {} already exists. Skipping import.", api.getContext(), - api.getVersion()); - } - } - - log.info("Successfully imported API '{}' ({}). Took {} ms", api.getName(), api.getVersion(), - System.currentTimeMillis() - start); - } catch (IOException e) { - log.error("IO error while importing API {}: {}", api.getId(), e.getMessage(), e); - } catch (VersionAlreadyExistsException e) { - log.warn("API version already exists for {}: {}. Skipping.", api.getName(), api.getVersion()); } catch (Exception e) { - log.error("Cannot export API '{}':{}", api.getName(), api.getVersion(), e); + log.error("IO error while importing API {}: {}", api.getId(), e.getMessage(), e); } } @@ -244,115 +110,4 @@ public class ExportToWso2 extends AbstractProcess { /* Helper methods */ /* --------------------------------------------------------------------- */ - private void updateSwagger(JsonObject swagger, Map apiMap, String description) { - JsonObject info = swagger.getAsJsonObject("info"); - if (info != null) { - info.addProperty("description", description); - } - - // Build servers array - JsonArray servers = new JsonArray(); - @SuppressWarnings("unchecked") - List> endpoints = (List>) apiMap.get("endpointURLs"); - if (endpoints != null) { - for (Map env : endpoints) { - @SuppressWarnings("unchecked") - Map urls = (Map) env.get("URLs"); - if (urls == null || urls.isEmpty()) - continue; - - JsonObject server = new JsonObject(); - urls.forEach((k, v) -> { - if (v != null && !v.isBlank()) { - if (k.equals("https")) { - server.addProperty("url", v); - } else if (k.equals("wss")) { - server.addProperty("url", v); - } - } - }); - server.addProperty("description", "Gateway: " + env.getOrDefault("environmentName", "")); - servers.add(server); - } - } - - swagger.remove("servers"); - swagger.add("servers", servers); - } - - private void addSubscriptionsToProps(Map props, Map subsMap) { - if (subsMap == null || !subsMap.containsKey("list")) - return; - @SuppressWarnings("unchecked") - List> list = (List>) subsMap.get("list"); - int i = 1; - for (Map sub : list) { - @SuppressWarnings("unchecked") - Map appInfo = (Map) sub.get("applicationInfo"); - if (appInfo == null) - continue; - props.put("subscription" + i, - appInfo.getOrDefault("name", "") + " (Owner: " + appInfo.getOrDefault("subscriber", "") + ")"); - i++; - } - } - - private void addEndpointsToProps(Map props, Map apiMap) { - if (apiMap == null || !apiMap.containsKey("endpointURLs")) - return; - @SuppressWarnings("unchecked") - List> envs = (List>) apiMap.get("endpointURLs"); - for (Map env : envs) { - @SuppressWarnings("unchecked") - Map urls = (Map) env.get("URLs"); - if (urls == null) - continue; - urls.forEach((k, v) -> props.put(k + " Endpoint", v)); - } - } - - private void addTagsToProps(Map props, List tags) { - if (tags != null && !tags.isEmpty()) { - props.put("tags", String.join(", ", tags)); - } - } - - private List createReferencesFromZip(List zipEntries, String group, APIInfo api) - throws IOException { - - List references = new ArrayList<>(); - for (ZipEntryData entry : zipEntries) { - String artifactId = api.getName() + "/" + api.getVersion() + "/" + entry.getName(); - - // Create the artifact (versioned) - try (ByteArrayInputStream is = new ByteArrayInputStream(entry.getContent())) { - client.createArtifactWithVersion(entry.getType().toString(), artifactId, api.getVersion(), is); - } - - ArtifactReference ref = new ArtifactReference(); - ref.setName(entry.getName()); - ref.setGroupId(entry.getType().toString()); - ref.setArtifactId(artifactId); - ref.setVersion(api.getVersion()); - references.add(ref); - } - return references; - } - - private void setMetaAndRules(ArtifactMetaData meta, Map props, List tags) { - EditableMetaData metaData = new EditableMetaData(); - metaData.setName(meta.getName()); - metaData.setDescription(meta.getDescription()); - metaData.setProperties(props); - metaData.setLabels(tags); - - client.updateArtifactMetaData(meta.getGroupId(), meta.getId(), metaData); - } - - private void createRule(ArtifactMetaData meta, String config, RuleType type) { - Rule rule = new Rule(); - rule.setConfig(config); - rule.setType(type); - client.createArtifactRule(meta.getGroupId(), meta.getId(), rule); - } }