package cz.trask.migration.impl.v32; import java.io.ByteArrayInputStream; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import cz.trask.migration.AbstractProcess; import cz.trask.migration.model.HttpResponse; import cz.trask.migration.model.TokenResponse; import cz.trask.migration.model.ZipEntryData; import cz.trask.migration.model.v32.ApplicationDetail; import cz.trask.migration.model.v32.ApplicationList; import cz.trask.migration.model.v32.ApplicationList.ApplicationInfo; import io.apicurio.registry.rest.client.RegistryClient; import io.apicurio.registry.rest.client.RegistryClientFactory; import io.apicurio.registry.rest.v2.beans.ArtifactMetaData; import io.apicurio.registry.rest.v2.beans.VersionSearchResults; import io.apicurio.registry.types.RuleType; import lombok.extern.log4j.Log4j2; @Log4j2 public class Wso2AppsToApicurio extends AbstractProcess { private final AtomicInteger appCounter = new AtomicInteger(1); private final RegistryClient client; public Wso2AppsToApicurio() throws Exception { this.client = RegistryClientFactory.create(config.getApicurio().getApiUrl()); } /** * Main entry point for the import process. * * @throws RuntimeException if any error occurs */ public void process() { try { log.info("Starting API import to Apicurio from WSO2..."); TokenResponse token = authenticateToWso2AndGetToken(); ApplicationList apps = getApplicationList(config.getSource().getAdminApiUrl(), token); if (apps == null || apps.getList() == null || apps.getList().size() == 0) { throw new IllegalStateException( "No Applications to export that match your criteria! Check the name of the Application you want to export."); } log.info("Found {} Applications", apps.getCount()); int maxThreads = config.getMaxThreads(); ExecutorService executor = Executors.newFixedThreadPool(maxThreads); for (ApplicationInfo app : apps.getList()) { final int index = appCounter.getAndIncrement(); executor.submit(() -> 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; } }