From a36ee218c2d2ac34e19415250aff83dff396e4bc Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Tue, 4 Nov 2025 13:29:30 +0100 Subject: [PATCH] export apps to apicurio --- client-truststore.jks | Bin 2985 -> 4945 bytes .../cz/trask/migration/AbstractProcess.java | 93 ++++++++-- src/main/java/cz/trask/migration/ApiSync.java | 10 +- .../impl/v32/Wso2AppsToApicurio.java | 161 ++++++++++++++++++ .../migration/impl/v32/Wso2v32ToApicurio.java | 40 +---- .../cz/trask/migration/impl/v32/ZipUtils.java | 9 +- .../impl/v45/ExportToWso2FromV32.java | 7 +- .../migration/model/ApplicationConfig.java | 2 + .../model/v32/ApplicationDetail.java | 103 +++++++++++ .../migration/model/v32/ApplicationList.java | 28 +++ src/main/resources/apicurio-migrator.yaml | 1 + 11 files changed, 395 insertions(+), 59 deletions(-) create mode 100644 src/main/java/cz/trask/migration/impl/v32/Wso2AppsToApicurio.java create mode 100644 src/main/java/cz/trask/migration/model/v32/ApplicationDetail.java create mode 100644 src/main/java/cz/trask/migration/model/v32/ApplicationList.java diff --git a/client-truststore.jks b/client-truststore.jks index df9d745e8e139c8f82d63e83a1eb0393a6ce67ef..a557f3b88e2fd1117776db67d4fee6d3fb2bcc53 100644 GIT binary patch delta 111 zcmZ1}eo>9*-`jt085kItfS7e7&kbf7;iA;^%;J)w#FEVXJl)g+U1L2X1_s7ietUM+ zPrl18wb8MSU5GO$KRGccBfq!=EVa+779zEQdGi(agUljpXTOX%>U{I(g`F}j;%$>2 Jbf}c`0RXmND%}78 delta 56 zcmcbpwo;tu-`jt085kItfS7qB&kg3u`TV?_PqANP-ki^Wj#(u6c$7)t processApplication(app, token, index, apps.getCount())); + } + + executor.shutdown(); + if (!executor.awaitTermination(10, TimeUnit.MINUTES)) { + log.warn("Timeout waiting for API import tasks to finish"); + } + log.info("Finished processing Applications."); + } catch (Exception e) { + log.error("Error while exporting Applications.", e); + throw new RuntimeException("Export failed", e); + } + } + + private void processApplication(ApplicationInfo app, TokenResponse tokenResponse, int index, int total) { + long start = System.currentTimeMillis(); + + try { + log.info("Processing API {} of {}", index, total); + + Map httpHeaders = Collections.singletonMap("Authorization", + "Bearer " + tokenResponse.getAccess_token()); + + HttpResponse exportedZip = makeRequest("GET", + config.getSource().getAdminApiUrl() + "/export/applications?appName=" + app.getName() + "&appOwner=" + + app.getOwner() + "&withKeys=true", + httpHeaders, + Collections.emptyMap(), true); + + List zipEntries = ZipUtils.extractFilesFromZip(exportedZip.getResponseBytes()); + + for (ZipEntryData entry : zipEntries) { + ApplicationDetail appDetail = mapper.readValue(entry.getContent(), ApplicationDetail.class); + + String group = ARTIFACT_GROUP_APPLICATIONS; + String mainArtifactId = appDetail.getName() + "(" + appDetail.getOwner() + ")"; + + VersionSearchResults existingArtifacts; + try { + existingArtifacts = client.listArtifactVersions(group, mainArtifactId, 0, Integer.MAX_VALUE); + } catch (Exception e) { + log.debug("No Application {} exists – will create it", mainArtifactId); + existingArtifacts = null; + } + + if (existingArtifacts == null) { + log.info("Creating new Application to Apicurio '{}' ({}).", appDetail.getName(), + appDetail.getOwner()); + // Create new artifact + ArtifactMetaData meta = client.createArtifact(group, mainArtifactId, + ARTIFACT_APPLICATION_DEFAULT_VERSION, null, null, + null, + appDetail.getName(), appDetail.getName(), null, null, null, + new ByteArrayInputStream(entry.getContent()), null); + + // Create the three required rules + createRule(meta, "NONE", RuleType.COMPATIBILITY); + createRule(meta, "NONE", RuleType.VALIDITY); + createRule(meta, "NONE", RuleType.INTEGRITY); + } + } + + log.info("Successfully imported Application '{}' ({}). Took {} ms", app.getName(), app.getOwner(), + System.currentTimeMillis() - start); + } catch (Exception e) { + log.error("Error processing Application {} of {}: {}", index, total, e.getMessage()); + } + } + + private ApplicationList getApplicationList(String adminApiUrl, TokenResponse tokenResponse) throws Exception { + + ApplicationList listOfApps = null; + + try { + String url = adminApiUrl.concat(String.format("/applications")); + + log.debug("Getting Applications with token: '" + tokenResponse.getAccess_token() + "' URL: " + url); + + Map httpHeaders = new HashMap<>(); + Map params = new HashMap<>(); + + httpHeaders.put("Authorization", "Bearer ".concat(tokenResponse.getAccess_token())); + + HttpResponse response = makeRequest("GET", url, httpHeaders, params); + + log.debug("Listing APIs: HTTP Code " + response.getResponseCode() + " Data: " + response.getResponse()); + + listOfApps = mapper.readValue(response.getResponse(), ApplicationList.class); + + if (response.getResponseCode() != 200) + log.error("Cannot list API. Something bad happened."); + } catch (Exception e) { + log.error("Cannot list API:" + e); + throw new Exception("Cannot list API:" + e.getMessage()); + } + return listOfApps; + } + +} diff --git a/src/main/java/cz/trask/migration/impl/v32/Wso2v32ToApicurio.java b/src/main/java/cz/trask/migration/impl/v32/Wso2v32ToApicurio.java index 8d3baec..5597c64 100644 --- a/src/main/java/cz/trask/migration/impl/v32/Wso2v32ToApicurio.java +++ b/src/main/java/cz/trask/migration/impl/v32/Wso2v32ToApicurio.java @@ -12,9 +12,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -28,28 +25,18 @@ import cz.trask.migration.model.ZipEntryData; import cz.trask.migration.model.v32.Subscriptions; import cz.trask.migration.model.v32.Subscriptions.ApplicationInfo; import cz.trask.migration.model.v32.Subscriptions.Subscription; -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.VersionSearchResults; import io.apicurio.registry.types.RuleType; +import lombok.extern.log4j.Log4j2; +@Log4j2 public class Wso2v32ToApicurio extends AbstractProcess { - private static final Logger log = LogManager.getLogger(Wso2v32ToApicurio.class); - private final AtomicInteger apiCounter = new AtomicInteger(1); - private final RegistryClient client; - - public Wso2v32ToApicurio() throws Exception { - this.client = RegistryClientFactory.create(config.getApicurio().getApiUrl()); - } - /** * Main entry point for the import process. * @@ -176,7 +163,7 @@ public class Wso2v32ToApicurio extends AbstractProcess { if (existingArtifacts == null) { // Create new artifact - List references = createReferencesFromZip(zipEntries, group, api); + List references = createReferencesFromZip(zipEntries, api); addSubscriptionsToReferences(references, subs, api); ArtifactMetaData meta = client.createArtifact(group, mainArtifactId, api.getVersion(), null, null, null, @@ -199,7 +186,7 @@ public class Wso2v32ToApicurio extends AbstractProcess { // Version missing – will create it below } - List references = createReferencesFromZip(zipEntries, group, api); + List references = createReferencesFromZip(zipEntries, api); addSubscriptionsToReferences(references, subs, api); if (!versionExists) { @@ -299,7 +286,7 @@ public class Wso2v32ToApicurio extends AbstractProcess { } } - private List createReferencesFromZip(List zipEntries, String group, APIInfo api) + private List createReferencesFromZip(List zipEntries, APIInfo api) throws IOException { List references = new ArrayList<>(); @@ -348,21 +335,4 @@ public class Wso2v32ToApicurio extends AbstractProcess { ref.setVersion(api.getVersion()); references.add(ref); } - - private void setArtifactMetaData(ArtifactMetaData meta, Map props) { - EditableMetaData metaData = new EditableMetaData(); - metaData.setName(meta.getName()); - metaData.setDescription(meta.getDescription()); - if (props != null) - metaData.setProperties(props); - - 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); - } } diff --git a/src/main/java/cz/trask/migration/impl/v32/ZipUtils.java b/src/main/java/cz/trask/migration/impl/v32/ZipUtils.java index 8cbcd42..664c8a7 100644 --- a/src/main/java/cz/trask/migration/impl/v32/ZipUtils.java +++ b/src/main/java/cz/trask/migration/impl/v32/ZipUtils.java @@ -8,16 +8,13 @@ import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import cz.trask.migration.model.FileType; import cz.trask.migration.model.ZipEntryData; +import lombok.extern.log4j.Log4j2; +@Log4j2 public class ZipUtils { - private static final Logger log = LogManager.getLogger(ZipUtils.class); - public static List extractFilesFromZip(byte[] data) throws IOException { List fileList = new ArrayList<>(); @@ -58,7 +55,7 @@ public class ZipUtils { return FileType.CERTIFICATE; } else if (lowerFileName.contains("/docs/")) { return FileType.DOCUMENTATION; - + } return FileType.UNKNOWN; } diff --git a/src/main/java/cz/trask/migration/impl/v45/ExportToWso2FromV32.java b/src/main/java/cz/trask/migration/impl/v45/ExportToWso2FromV32.java index 72a3a0d..b87af84 100644 --- a/src/main/java/cz/trask/migration/impl/v45/ExportToWso2FromV32.java +++ b/src/main/java/cz/trask/migration/impl/v45/ExportToWso2FromV32.java @@ -15,9 +15,6 @@ import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import com.fasterxml.jackson.core.type.TypeReference; import cz.trask.migration.AbstractProcess; @@ -40,11 +37,11 @@ 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 lombok.extern.log4j.Log4j2; +@Log4j2 public class ExportToWso2FromV32 extends AbstractProcess { - private static final Logger log = LogManager.getLogger(ExportToWso2FromV32.class); - private final AtomicInteger apiCounter = new AtomicInteger(1); private final RegistryClient client; diff --git a/src/main/java/cz/trask/migration/model/ApplicationConfig.java b/src/main/java/cz/trask/migration/model/ApplicationConfig.java index 3880002..95e921f 100644 --- a/src/main/java/cz/trask/migration/model/ApplicationConfig.java +++ b/src/main/java/cz/trask/migration/model/ApplicationConfig.java @@ -26,6 +26,8 @@ public class ApplicationConfig { private String registrationApiUrl; @JsonProperty("publisher_api_url") private String publisherApiUrl; + @JsonProperty("admin_api_url") + private String adminApiUrl; @JsonProperty("devportal_api_url") private String devPortalApiUrl; @JsonProperty("publisher_token_url") diff --git a/src/main/java/cz/trask/migration/model/v32/ApplicationDetail.java b/src/main/java/cz/trask/migration/model/v32/ApplicationDetail.java new file mode 100644 index 0000000..5d2843f --- /dev/null +++ b/src/main/java/cz/trask/migration/model/v32/ApplicationDetail.java @@ -0,0 +1,103 @@ +package cz.trask.migration.model.v32; + +import lombok.Data; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import java.util.List; +import java.util.Map; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ApplicationDetail { + private int id; + private String name; + private String uuid; + private Subscriber subscriber; + private List subscribedAPIs; + private List keys; + private Map> keyManagerWiseOAuthApp; + private String tier; + private String status; + private String groupId; + private String owner; + private Map applicationAttributes; + private String tokenType; + private int subscriptionCount; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class Subscriber { + private String name; + private int id; + private int tenantId; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class SubscribedAPI { + private int subscriptionId; + private Tier tier; + private Subscriber subscriber; + private ApiId apiId; + private Application application; + private String subStatus; + private String subCreatedStatus; + private List keys; + private String uuid; + private boolean isBlocked; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class Tier { + private String name; + private String displayName; + private int requestsPerMin; + private int requestCount; + private int unitTime; + private String timeUnit; + private boolean stopOnQuotaReached; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class ApiId { + private String providerName; + private String apiName; + private String version; + private int id; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class Application { + private int id; + private String name; + private String uuid; + private Subscriber subscriber; + private List subscribedAPIs; + private List keys; + private Map keyManagerWiseOAuthApp; + private Map applicationAttributes; + private int subscriptionCount; + } + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class KeyManagerApp { + private String clientId; + private String clientName; + private String callBackURL; + private String clientSecret; + private Map parameters; + private boolean isSaasApplication; + private Map appAttributes; + } +} diff --git a/src/main/java/cz/trask/migration/model/v32/ApplicationList.java b/src/main/java/cz/trask/migration/model/v32/ApplicationList.java new file mode 100644 index 0000000..6d75a20 --- /dev/null +++ b/src/main/java/cz/trask/migration/model/v32/ApplicationList.java @@ -0,0 +1,28 @@ +package cz.trask.migration.model.v32; + +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ApplicationList { + private int count; + private String next; + private String previous; + private List list; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class ApplicationInfo { + private String applicationId; + private String name; + private String owner; + private String status; + private Object groupId; + } +} diff --git a/src/main/resources/apicurio-migrator.yaml b/src/main/resources/apicurio-migrator.yaml index f644a0d..27205af 100644 --- a/src/main/resources/apicurio-migrator.yaml +++ b/src/main/resources/apicurio-migrator.yaml @@ -1,6 +1,7 @@ source: registration_api_url: https://localhost:9444/client-registration/v0.17/register publisher_api_url: https://localhost:9444/api/am/publisher + admin_api_url: https://localhost:9444/api/am/admin/v1 devportal_api_url: https://localhost:9444/api/am/store publisher_token_url: https://localhost:9444/oauth2/token wso2_user: YWRtaW46YWRtaW4=