From ff9bfccee85ce8b6bcef01233f969de32655f4ef Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Wed, 1 Oct 2025 13:15:32 +0200 Subject: [PATCH] first commit --- .gitignore | 8 + client-truststore.jks | Bin 0 -> 1990 bytes pom.xml | 88 ++++ .../cz/trask/apioperator/AbstractProcess.java | 271 +++++++++++ .../java/cz/trask/apioperator/ApiSync.java | 32 ++ .../java/cz/trask/apioperator/Import.java | 424 ++++++++++++++++++ .../apioperator/config/ConfigManager.java | 162 +++++++ .../cz/trask/apioperator/model/APIInfo.java | 92 ++++ .../cz/trask/apioperator/model/APIList.java | 31 ++ .../apioperator/model/ApiDefinition.java | 96 ++++ .../trask/apioperator/model/EventAPIInfo.java | 97 ++++ .../cz/trask/apioperator/model/FileType.java | 9 + .../trask/apioperator/model/HttpResponse.java | 49 ++ .../apioperator/model/RegisterResponse.java | 62 +++ .../apioperator/model/StartParameters.java | 35 ++ .../apioperator/model/TokenResponse.java | 53 +++ .../trask/apioperator/model/ZipEntryData.java | 43 ++ .../trask/apioperator/utils/ZipExtractor.java | 66 +++ src/main/resources/api-operator.properties | 23 + src/main/resources/log4j2.properties | 28 ++ 20 files changed, 1669 insertions(+) create mode 100644 .gitignore create mode 100644 client-truststore.jks create mode 100644 pom.xml create mode 100644 src/main/java/cz/trask/apioperator/AbstractProcess.java create mode 100644 src/main/java/cz/trask/apioperator/ApiSync.java create mode 100644 src/main/java/cz/trask/apioperator/Import.java create mode 100644 src/main/java/cz/trask/apioperator/config/ConfigManager.java create mode 100644 src/main/java/cz/trask/apioperator/model/APIInfo.java create mode 100644 src/main/java/cz/trask/apioperator/model/APIList.java create mode 100644 src/main/java/cz/trask/apioperator/model/ApiDefinition.java create mode 100644 src/main/java/cz/trask/apioperator/model/EventAPIInfo.java create mode 100644 src/main/java/cz/trask/apioperator/model/FileType.java create mode 100644 src/main/java/cz/trask/apioperator/model/HttpResponse.java create mode 100644 src/main/java/cz/trask/apioperator/model/RegisterResponse.java create mode 100644 src/main/java/cz/trask/apioperator/model/StartParameters.java create mode 100644 src/main/java/cz/trask/apioperator/model/TokenResponse.java create mode 100644 src/main/java/cz/trask/apioperator/model/ZipEntryData.java create mode 100644 src/main/java/cz/trask/apioperator/utils/ZipExtractor.java create mode 100644 src/main/resources/api-operator.properties create mode 100644 src/main/resources/log4j2.properties diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d9081e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +target +bin +.settings +.classpath +.project +*.log +.idea +.vscode \ No newline at end of file diff --git a/client-truststore.jks b/client-truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..9fe4b89d054f80bebb1804d45dab8c5c722e3be9 GIT binary patch literal 1990 zcmezO_TO6u1_mZL=FQ1ZPRz;3FD}tF)-z&YV4OK~?F%gi)(AaQ14{-5=CuY*%qtC= zm?kb@W@2PwVu{_rxY&S~jZ>@5qwPB{BO^B}gF%WRw*e;`b0`a&FjHtSjKjghNzBYs2+K?@H{>6C)$T(N`-{ z+b;ao`or@u;Pm|?X7=X(?z_*9e?E?=rgwY^V@U1;5E^``@df^ zX3nv5;-TbP+ZMB!?b*4N?+@W>w(JuDmR&3X=O`CO`;S%S4 zmQ`j8QZMz)T%InZ_&fF2X2nDG%9826+-Gc7H?>}KtZCh&V3sXcv3WOFM{&=ce+*yq z1cEtN2kI*OC33WKAtz_0^dYqUxyX1 z{=>^`0G3u|0i_xaZ8k<$R(57aIEx9KW@PzUSeThuJ|IT}Fcku$fsw(V{qGuw#)`M! z3y*O&uAAv}?N-o|riJ=(d-`v33NGC;|_ag|d+y4RPA8TB}XsQ{M*v)kJVc4E?TKKeQw>&jmN{b zg0nSJmNwBdgk^GF_5mRHXk%N@S9O)B|sXnwrF_|?t)bLVU94!@H& zn_zKro$flVBbVwd)_Bf(?Hm-ablK~VJO3{}wN8OEE?1z5J5rdjFTiEV^lP)%{tH<& zs$I)Xk2fT2yK(l>o_hPY|M$O57Bu~= z@YnlsPy4nhy!$;B6aOjyUHG`b>(O^j{pGf4Td&Q@+thV?az%LHad(DSX-dTw3LTyW z?^eidXnJP9zw^uV(6?*6tvht)yTtH%EY8+j_3hr3Qm*4_y5Ek!ob=#{8mEu_)*W9q zUMS{cZ(aX9_;xh$S-O_XxlA}^PVk1?{HM10c|?fE3GSmbO9y-2Z|LagbUK!^^7j5N z=G+~+3$Je3=e+Zv*M+~^MENIZIrnz@@V$3h5fXKer8a1`^p1+JOI~f36nSj9U_X0o zhxvA%eNP|G(J#JGzV&B0gVxlD_2)V@x|cL(@ZVO*>-_UJtdOup@7N2jxM*0Y=anmvEdg&luOHlM0Ioi%mB2Zw(%9yJQQQB0{? zzF$C4vCenl(SGqe{LB9ql_^!fX_0Zsl|E^6e8y?f_bWmAbkKg4WVu;iccmy=fl z5+7|S6}z-)+QNBRkKcX1@H}IF-K1Z>&i9PO67||H96a^mQNMuJzKG>_jZf6;^Ph}v Vx?OX>uGl=*BvIA={J$M3TL32}$UFc5 literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..10b7ac9 --- /dev/null +++ b/pom.xml @@ -0,0 +1,88 @@ + + 4.0.0 + cz.trask.apioperator + api-operator + jar + 1.0-SNAPSHOT + api-operator + http://maven.apache.org + + + 11 + ${java.version} + ${java.version} + UTF-8 + + + + + + io.apicurio + apicurio-registry-client + 3.0.0.M2 + + + org.apache.logging.log4j + log4j-core + 2.24.2 + + + com.google.code.gson + gson + 2.13.1 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.1 + + + + shade + + + false + + + cz.trask.apioperator.ApiSync + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.1 + + + + cz.trask.apioperator.ApiSync + + + + + + + + + + wso2.releases + WSO2 internal Repository + https://maven.wso2.org/nexus/content/repositories/releases/ + + true + daily + ignore + + + + \ No newline at end of file diff --git a/src/main/java/cz/trask/apioperator/AbstractProcess.java b/src/main/java/cz/trask/apioperator/AbstractProcess.java new file mode 100644 index 0000000..5601cfb --- /dev/null +++ b/src/main/java/cz/trask/apioperator/AbstractProcess.java @@ -0,0 +1,271 @@ +package cz.trask.apioperator; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.StringReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ssl.HttpsURLConnection; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.stream.JsonReader; + +import cz.trask.apioperator.config.ConfigManager; +import cz.trask.apioperator.model.HttpResponse; +import cz.trask.apioperator.model.RegisterResponse; +import cz.trask.apioperator.model.TokenResponse; + +public abstract class AbstractProcess { + + private static Logger log = LogManager.getLogger(AbstractProcess.class); + + protected AbstractProcess() { + + setTrustStoreCredentials("TRUSTSTORE_PATH", "TRUSTSTORE_PASSWORD"); + + javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() { + public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { + return true; + } + }); + + } + + protected static String getTrustStorePath(String trustStorePath) { + String path = System.getProperty("user.dir") + File.separatorChar + + ConfigManager.getInstance().getTruststorePath(); + if (!new File(path).canRead()) + return null; + return path; + } + + protected static void setTrustStoreCredentials(String trustStorePath, String trustStorePassword) { + log.info(getTrustStorePath(trustStorePath)); + System.setProperty("javax.net.ssl.trustStore", getTrustStorePath(trustStorePath)); + System.setProperty("javax.net.ssl.trustStorePassword", ConfigManager.getInstance().getTruststorePassword()); + } + + /** + * Retrieve access token based on clientId and clientSecret + * + * @param reg - client application object with clientId and clientSecret + * @param scope - requested OAuth2 scope + * @throws Exception + */ + protected TokenResponse getToken(String publisherurl, String wso2User, RegisterResponse reg, String scope) + throws Exception { + + byte[] decoded = Base64.getDecoder().decode(wso2User); + String decodedstring = new String(decoded); + String[] decodedstringparts = decodedstring.split(":"); + + String username = decodedstringparts[0]; + String password = decodedstringparts[1]; + + log.debug("Getting token with Username: '" + wso2User + "' URL: " + publisherurl); + + Map httpHeaders = new HashMap<>(); + + httpHeaders.put("Authorization", "Basic ".concat(Base64.getEncoder() + .encodeToString(reg.getClientId().concat(":").concat(reg.getClientSecret()).getBytes()))); + httpHeaders.put("Content-Type", "application/x-www-form-urlencoded"); + + String data = "grant_type=password&username=".concat(username).concat("&password=") + .concat(URLEncoder.encode(password, "UTF-8")).concat("&scope=").concat(scope); + HttpResponse response = makeDataRequest(publisherurl, httpHeaders, data); + + log.debug("Token response: HTTP Code " + response.getResponseCode() + " Json: " + response.getResponse()); + + Gson gson = new GsonBuilder().create(); + JsonReader reader = new JsonReader(new StringReader(response.getResponse())); + reader.setLenient(true); + TokenResponse resp = gson.fromJson(reader, TokenResponse.class); + return resp; + } + + /** + * Register client application to get clientId and clientSecret + * + * @throws Exception + */ + protected RegisterResponse register(String publisherurl, String wso2User) throws Exception { + + log.debug("Registering with Username: '" + wso2User + "' URL: " + publisherurl); + + byte[] decodedUserBytes = Base64.getDecoder().decode(wso2User); + String decodeduserappkey = new String(decodedUserBytes); + String[] decodeduserparts = decodeduserappkey.split(":"); + String decodeduser = decodeduserparts[0]; + + Map httpHeaders = new HashMap<>(); + + httpHeaders.put("Authorization", "Basic ".concat(wso2User)); + httpHeaders.put("Content-Type", "application/json"); + + String data = "{\"callbackUrl\": \"www.google.lk\",\"clientName\": \"rest_api_publisher" + decodeduser + + "\",\"owner\": \"" + decodeduser + "\",\"grantType\": \"password refresh_token\",\"saasApp\": true}"; + HttpResponse response = makeDataRequest(publisherurl, httpHeaders, data); + + log.debug( + "Register API response: HTTP Code " + response.getResponseCode() + " Json: " + response.getResponse()); + + Gson gson = new GsonBuilder().create(); + JsonReader reader = new JsonReader(new StringReader(response.getResponse())); + reader.setLenient(true); + RegisterResponse resp = gson.fromJson(reader, RegisterResponse.class); + return resp; + } + + /** + * Common function used for http request + * + * @param method - http method + * @param urlStr - url to dev poral + * @param httpHeaders + * @param params - currently is not used + * @throws Exception + */ + protected HttpResponse makeRequest(String method, String urlStr, Map httpHeaders, + Map params) throws Exception { + return makeRequest(method, urlStr, httpHeaders, params, false); + } + + /** + * Common function used for http request + * + * @param method - http method + * @param urlStr - url to dev poral + * @param httpHeaders + * @param data - request data + * @param binary - binary or text mode + * @throws Exception + */ + protected HttpResponse makeRequest(String method, String urlStr, Map httpHeaders, + Map params, boolean binary) throws Exception { + + log.info("Calling URL: " + urlStr); + String query = ""; + for (String key : params.keySet()) { + query = query.concat(URLEncoder.encode(key, "UTF-8")).concat("=") + .concat(URLEncoder.encode(params.get(key), "UTF-8")).concat("&"); + } + + if (query.length() > 1 && "GET".equals(method)) { + urlStr = urlStr.concat("?").concat(query); + } + + URL url = new URL(urlStr); + + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod(method); + con.setDoInput(true); + + for (String key : httpHeaders.keySet()) { + con.addRequestProperty(key, httpHeaders.get(key)); + } + + if (query.length() > 1 && "POST".equals(method)) { + con.setDoOutput(true); + OutputStream out = con.getOutputStream(); + out.write(query.getBytes("UTF-8")); + } + + InputStream in = con.getInputStream(); + + String res = ""; + byte[] buf = new byte[4096]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int read = in.read(buf); + + while (read != -1) { + if (binary) + baos.write(buf, 0, read); + else + res = res.concat(new String(buf, 0, read)); + + read = in.read(buf); + } + + baos.flush(); + + HttpResponse resp = new HttpResponse(); + resp.setHeaders(con.getHeaderFields()); + if (binary) + resp.setResponseBytes(baos.toByteArray()); + else + resp.setResponse(res); + resp.setResponseCode(con.getResponseCode()); + + con.disconnect(); + + log.info("Response code: " + resp.getResponseCode()); + // log.info("Response: " + resp.getResponse()); + + return resp; + } + + /** + * Common function used for http request + * + * @param urlStr - url to dev poral + * @param httpHeaders + * @param data - request data + * @throws Exception + */ + protected HttpResponse makeDataRequest(String urlStr, Map httpHeaders, String data) + throws Exception { + + byte[] json = data.getBytes(Charset.forName("UTF-8")); + + URL url = new URL(urlStr); + + HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setDoInput(true); + con.setDoOutput(true); + + for (String key : httpHeaders.keySet()) { + con.addRequestProperty(key, httpHeaders.get(key)); + } + + con.addRequestProperty("Content-Length", "" + json.length); + + OutputStream out = con.getOutputStream(); + out.write(json); + + InputStream in = con.getInputStream(); + + String res = ""; + byte[] buf = new byte[4096]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int read = in.read(buf); + + while (read != -1) { + res = res.concat(new String(buf, 0, read)); + read = in.read(buf); + } + + baos.flush(); + + HttpResponse resp = new HttpResponse(); + resp.setHeaders(con.getHeaderFields()); + resp.setResponse(res); + resp.setResponseCode(con.getResponseCode()); + + return resp; + } +} diff --git a/src/main/java/cz/trask/apioperator/ApiSync.java b/src/main/java/cz/trask/apioperator/ApiSync.java new file mode 100644 index 0000000..fb37976 --- /dev/null +++ b/src/main/java/cz/trask/apioperator/ApiSync.java @@ -0,0 +1,32 @@ +package cz.trask.apioperator; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import cz.trask.apioperator.model.StartParameters; + +public class ApiSync { + + private static Logger log = LogManager.getLogger(ApiSync.class); + + protected final static String resourceName = "api-operator.properties"; + + public static void main(String[] args) throws Exception { + if (args == null) { + printHelp(); + } else { + + String commandLine = String.join("", args).trim(); + StartParameters sp = StartParameters.parse(commandLine); + + if (sp.getCommand().equalsIgnoreCase("import")) { + Import imp = new Import(sp); + imp.process(); + } + } + } + + private static void printHelp() { + System.out.println("Not enough parameters.\nRun command in this format:\njava -jar shaded.jar [import/export]"); + } +} diff --git a/src/main/java/cz/trask/apioperator/Import.java b/src/main/java/cz/trask/apioperator/Import.java new file mode 100644 index 0000000..880275c --- /dev/null +++ b/src/main/java/cz/trask/apioperator/Import.java @@ -0,0 +1,424 @@ +package cz.trask.apioperator; + +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.stream.JsonReader; + +import cz.trask.apioperator.config.ConfigManager; +import cz.trask.apioperator.model.APIInfo; +import cz.trask.apioperator.model.APIList; +import cz.trask.apioperator.model.HttpResponse; +import cz.trask.apioperator.model.RegisterResponse; +import cz.trask.apioperator.model.StartParameters; +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.GroupMetaData; +import io.apicurio.registry.rest.v2.beans.Rule; +import io.apicurio.registry.rest.v2.beans.VersionMetaData; +import io.apicurio.registry.rest.v2.beans.VersionSearchResults; +import io.apicurio.registry.types.RuleType; + +public class Import extends AbstractProcess { + + private static Logger log = LogManager.getLogger(Import.class); + + StartParameters sp; + RegistryClient client; + static int i = 1; + private ConfigManager config; + + public Import(StartParameters sp) throws Exception { + this.sp = sp; + this.config = ConfigManager.getInstance(); + client = RegistryClientFactory.create(config.getApicurioApiUrl()); + // createGroup(); + } + + private void createGroup() { + GroupMetaData group = new GroupMetaData(); + group.setCreatedOn(new Date()); + group.setCreatedBy("admin"); + group.setDescription("My Test Group"); + group.setId("wso2-apis"); + client.createArtifactGroup(group); + } + + /** + * Process Export API + * + * @throws Exception - all exceptions in the code are thrown for handling in + * CICD purpose + */ + public void process() throws Exception { + log.info("exporting APIs..."); + try { + log.info("Register user for calling Admins APIs..."); + RegisterResponse registerResponse = register(config.getSourceRegistrationApiUrl(), + config.getSourceWso2User()); + log.info("Registered with clientId: " + registerResponse.getClientId()); + + log.info("Getting token for clientId:" + registerResponse.getClientId()); + TokenResponse tokenResponse = getToken(config.getSourcePublisherTokenUrl(), config.getSourceWso2User(), + registerResponse, + "apim:api_view apim:api_create apim:api_manage apim:api_delete apim:api_publish apim:subscription_view apim:subscription_block apim:subscription_manage apim:external_services_discover apim:threat_protection_policy_create apim:threat_protection_policy_manage apim:document_create apim:document_manage apim:mediation_policy_view apim:mediation_policy_create apim:mediation_policy_manage apim:client_certificates_view apim:client_certificates_add apim:client_certificates_update apim:ep_certificates_view apim:ep_certificates_add apim:ep_certificates_update apim:publisher_settings apim:pub_alert_manage apim:shared_scope_manage apim:app_import_export apim:api_import_export apim:api_product_import_export apim:api_generate_key apim:common_operation_policy_view apim:common_operation_policy_manage apim:comment_write apim:comment_view apim:admin"); + log.debug("Token for clientId is: " + tokenResponse.getAccess_token()); + + log.info("Getting list of APIs ..."); + APIList apis = getList(config.getSourcePublisherApiUrl(), tokenResponse); + + if (apis == null || apis.getList() == null || apis.getList().length == 0) { + throw new Exception( + "There is no APIs to export that meets yours criteria! Please, check the name of API you want to export and try again!"); + } + + log.info("Found " + apis.getCount() + " APIs"); + + int maxThreads = config.getMaxThreads(); + log.info("Starting API processing with " + maxThreads + " threads"); + ExecutorService executor = Executors.newFixedThreadPool(maxThreads); + for (APIInfo api : apis.getList()) { + executor.execute(new Runnable() { + @Override + public void run() { + processApi(api, tokenResponse, i++, apis.getCount()); + } + }); + } + executor.shutdown(); + while (!executor.isTerminated()) { + Thread.sleep(500); + } + log.info("Finished processing APIs."); + } catch (Exception e) { + log.error("Error while exporting APIs. ", e); + throw new Exception("Error while exporting APIs!"); + } + } + + private void processApi(APIInfo api, TokenResponse tokenResponse, int i, int apiCount) { + long start = System.currentTimeMillis(); + String apiStatus = api.getLifeCycleStatus(); + if (!apiStatus.contains("PUBLISHED") && !apiStatus.contains("DEPRECATED")) { + log.info("Skipping API " + i + " of " + apiCount + "with ID " + api.getId() + + " because it is not published."); + return; + } + try { + log.info("Processing API " + i + " of " + apiCount); + + Map httpHeaders = new HashMap<>(); + Map params = new HashMap<>(); + + httpHeaders.put("Authorization", "Bearer ".concat(tokenResponse.getAccess_token())); + + String type = api.getType(); + + switch (type) { + case "HTTP": + type = "OPENAPI"; + break; + case "GRAPHQL": + type = "GRAPHQL"; + break; + case "WS": + type = "ASYNCAPI"; + break; + case "SOAP": + type = "WSDL"; + break; + default: + } + + try { + Gson gson = new GsonBuilder().create(); + HttpResponse responseApi = makeRequest("GET", + config.getSourceDevportalApiUrl().concat(String.format("/apis/%s", api.getId())), httpHeaders, + params); + HttpResponse responseSubs = makeRequest("GET", + config.getSourcePublisherApiUrl().concat(String.format("/subscriptions?apiId=%s", api.getId())), + httpHeaders, params); + HttpResponse responseApiSwagger = makeRequest("GET", + config.getSourcePublisherApiUrl().concat(String.format("/apis/%s/swagger", api.getId())), + httpHeaders, params); + + HttpResponse exportedApiZip = makeRequest("GET", + config.getSourcePublisherApiUrl().concat(String.format("/apis/export?apiId=%s", api.getId())), + httpHeaders, params, true); + + List zipEntries = ZipExtractor.extractFilesFromZip(exportedApiZip.getResponseBytes()); + + Map mapSubs = gson.fromJson(responseSubs.getResponse(), Map.class); + Map mapApi = gson.fromJson(responseApi.getResponse(), Map.class); + + List tags = new ArrayList(); + + Map map = new HashMap(); + map.put("Version ", " " + api.getVersion()); + map.put("Status ", " " + apiStatus); + addSubscriptionsToMap(map, mapSubs); + addEndpointsToMap(map, mapApi); + addTagsToMap(map, (List) mapApi.get("tags")); + + String group = config.getDefaultApiGroup(); + + String ApiDesc = api.getDescription() != null ? api.getDescription() : ""; + + String ApiDescNew = ApiDesc + " ***** " + "PUBLISHER URL ***** " + + config.getPublisherUrlPattern().replace("{API_ID}", api.getId()) + " ***** " + + "DEVPORTAL URL ***** " + config.getDevportalUrlPattern().replace("{API_ID}", api.getId()); + + String ApiDescSwagger = ApiDesc + "\r\n\r\n\n\n" + "PUBLISHER URL:" + + config.getPublisherUrlPattern().replace("{API_ID}", api.getId()) + "\r\n\n\n" + + "DEVPORTAL URL:" + config.getDevportalUrlPattern().replace("{API_ID}", api.getId()); + + JsonObject swagger = JsonParser.parseString(responseApiSwagger.getResponse()).getAsJsonObject(); + + JsonObject info = swagger.getAsJsonObject("info"); + info.addProperty("description", ApiDescSwagger); + + JsonArray serversJsonArray = new JsonArray(); + + if (mapApi != null && !mapApi.isEmpty()) { + List list = (List) mapApi.get("endpointURLs"); + if (list != null && !list.isEmpty()) { + for (Iterator it = list.iterator(); it.hasNext();) { + Map environment = it.next(); + Map urls = (Map) environment.get("URLs"); + + if (urls != null && !urls.isEmpty()) { + JsonObject servers = new JsonObject(); + + String https = (String) urls.get("https"); + String wss = (String) urls.get("wss"); + + if (https != null) { + servers.addProperty("url", https); + } + if (wss != null) { + servers.addProperty("url", wss); + } + + servers.addProperty("description", + "Gateway: " + (String) environment.get("environmentName")); + serversJsonArray.add(servers); + } + } + } + } + + swagger.remove("servers"); + swagger.add("servers", serversJsonArray); + + swagger.getAsJsonObject("info").addProperty("description", ApiDescSwagger); + + log.info("Trying to call ApiCurio..."); + + VersionMetaData checkIfVersionExist = null; + VersionSearchResults checkIfApiExist = null; + + String mainArtifactId = api.getName().concat(api.getContext()); + + try { + checkIfApiExist = client.listArtifactVersions(group, mainArtifactId, 0, 9999); + log.debug("API " + api.getContext() + " exists ..."); + try { + checkIfVersionExist = client.getArtifactVersionMetaData(group, mainArtifactId, + api.getVersion()); + log.debug("Version " + api.getVersion() + " for API " + api.getContext() + " exists ..."); + } catch (Exception e) { + log.debug("No version " + api.getVersion() + " for API " + api.getContext() + " exists ..."); + } + } catch (Exception e) { + log.debug("No API " + api.getContext() + " exists, so creating ..."); + } + + if (checkIfApiExist == null) { + List references = new ArrayList<>(); + for (ZipEntryData entry : zipEntries) { + String artifactId = api.getName().concat("/").concat(api.getVersion()).concat("/") + .concat(entry.getName()); + ArtifactMetaData mtd = client.createArtifactWithVersion(entry.getType().toString(), artifactId, + api.getVersion(), new ByteArrayInputStream(entry.getContent())); + + ArtifactReference ref = new ArtifactReference(); + ref.setName(entry.getName()); + ref.setGroupId(entry.getType().toString()); + ref.setArtifactId(artifactId); + ref.setVersion(api.getVersion()); + references.add(ref); + } + + ArtifactMetaData mtd = client.createArtifact(group, mainArtifactId, api.getVersion(), null, null, + null, api.getName(), ApiDescNew, null, null, null, + new ByteArrayInputStream(swagger.toString().getBytes()), references); + EditableMetaData props = new EditableMetaData(); + props.setName(api.getName()); + props.setDescription(ApiDescNew); + props.setProperties(map); + props.setLabels(tags); + + client.updateArtifactMetaData(mtd.getGroupId(), mtd.getId(), props); + updateRules(mtd, "NONE", "COMPATIBILITY"); + updateRules(mtd, "NONE", "VALIDITY"); + updateRules(mtd, "NONE", "INTEGRITY"); + + } else if (checkIfVersionExist == null) { + List references = new ArrayList<>(); + for (ZipEntryData entry : zipEntries) { + String artifactId = api.getName().concat("/").concat(api.getVersion()).concat("/") + .concat(entry.getName()); + ArtifactMetaData mtd = client.createArtifactWithVersion(entry.getType().toString(), artifactId, + api.getVersion(), new ByteArrayInputStream(entry.getContent())); + + ArtifactReference ref = new ArtifactReference(); + ref.setName(entry.getName()); + ref.setGroupId(entry.getType().toString()); + ref.setArtifactId(artifactId); + ref.setVersion(api.getVersion()); + references.add(ref); + } + + ArtifactMetaData mtd = client.updateArtifact(group, mainArtifactId, api.getVersion(), api.getName(), + ApiDescNew, new ByteArrayInputStream(swagger.toString().getBytes()), references); + EditableMetaData props = new EditableMetaData(); + props.setName(api.getName()); + props.setDescription(ApiDescNew); + props.setProperties(map); + props.setLabels(tags); + client.updateArtifactMetaData(mtd.getGroupId(), mtd.getId(), props); + } + + log.info("ApiCurio called successfully..."); + + } catch (VersionAlreadyExistsException e) { + log.error(e); + } + + log.info("API successfully posted to APICurio. APIName='" + api.getName() + "'. Done in " + + (System.currentTimeMillis() - start) + "ms"); + + } catch (Exception e) { + log.error("Cannot export API: " + api.getName() + " " + api.getVersion(), e); + } + } + + private void addTagsToMap(Map map, List list) { + if (list != null && !list.isEmpty()) { + map.put("Tags ", " " + list.toString().replace("[", "").replace("]", "")); + } + } + + private void updateRules(ArtifactMetaData mtd, String config, String ruletype) { + Rule rule = new Rule(); + rule.setConfig(config); + rule.setType(RuleType.fromValue(ruletype)); + client.createArtifactRule(mtd.getGroupId(), mtd.getId(), rule); + } + + private void addSubscriptionsToMap(Map map, Map mapSubs) { + if (mapSubs != null && !mapSubs.isEmpty()) { + List list = (List) mapSubs.get("list"); + int i = 0; + if (list != null && !list.isEmpty()) { + for (Iterator it = list.iterator(); it.hasNext();) { + i++; + Map subscription = it.next(); + Map applicationInfo = (Map) subscription.get("applicationInfo"); + if (applicationInfo != null && !applicationInfo.isEmpty()) + map.put("Subscription" + i + " ", " " + (String) applicationInfo.get("name") + " " + "(Owner: " + + (String) applicationInfo.get("subscriber") + ")"); + } + } + } + } + + private void addEndpointsToMap(Map map, Map mapApi) { + if (mapApi != null && !mapApi.isEmpty()) { + List list = (List) mapApi.get("endpointURLs"); + if (list != null && !list.isEmpty()) { + for (Iterator it = list.iterator(); it.hasNext();) { + Map environment = it.next(); + Map urls = (Map) environment.get("URLs"); + if (urls != null && !urls.isEmpty()) { + String http = (String) urls.get("http"); + String https = (String) urls.get("https"); + String ws = (String) urls.get("ws"); + String wss = (String) urls.get("wss"); + if (http != null) { + map.put("HTTP Endpoint", http); + } else if (https != null) { + map.put("HTTPS Endpoint", https); + } else if (ws != null) { + map.put("WS Endpoint", ws); + } else if (wss != null) { + map.put("WSS Endpoint", wss); + } + } + } + } + } + } + + + /** + * Retrieve the list of APIs by name. + * + * @param tokenResponse - WSO2 APIM access token + * @throws Exception + */ + protected APIList getList(String publisherurl, TokenResponse tokenResponse) throws Exception { + + APIList listOfApis = null; + + try { + String url = publisherurl.concat(String.format("/apis?limit=9999&offset=0")); + + log.debug("Getting APIs 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()); + + Gson gson = new GsonBuilder().create(); + JsonReader reader = new JsonReader(new StringReader(response.getResponse())); + reader.setLenient(true); + listOfApis = gson.fromJson(reader, APIList.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 listOfApis; + } +} diff --git a/src/main/java/cz/trask/apioperator/config/ConfigManager.java b/src/main/java/cz/trask/apioperator/config/ConfigManager.java new file mode 100644 index 0000000..e493982 --- /dev/null +++ b/src/main/java/cz/trask/apioperator/config/ConfigManager.java @@ -0,0 +1,162 @@ +package cz.trask.apioperator.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Properties; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConfigManager { + + private static Logger log = LogManager.getLogger(ConfigManager.class); + + private static ConfigManager instance = null; + + private final static String PROPERTY_FILENAME = "api-operator.properties"; + + // Property fields + private String sourceRegistrationApiUrl; + private String sourcePublisherApiUrl; + private String sourceDevportalApiUrl; + private String sourcePublisherTokenUrl; + private String sourceWso2User; + private String targetRegistrationApiUrl; + private String targetPublisherApiUrl; + private String targetDevportalApiUrl; + private String targetPublisherTokenUrl; + private String targetWso2User; + private String truststorePath; + private String truststorePassword; + private String publisherUrlPattern; + private String devportalUrlPattern; + private String apicurioApiUrl; + private String defaultApiGroup; + private int maxThreads; + + private ConfigManager() { + Properties properties = new Properties(); + + log.info("Loading property file '" + PROPERTY_FILENAME + "'"); + InputStream in = null; + + try { + File f = new File(PROPERTY_FILENAME); + log.info("External property file location: " + f.getAbsolutePath()); + in = new FileInputStream(f); + log.info("External property file found."); + } catch (Exception e) { + log.info("External property file not found."); + try { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + in = loader.getResourceAsStream(PROPERTY_FILENAME); + log.info("Internal property file found."); + } catch (Exception ex) { + log.info("Internal property file not found."); + } + } + + try { + properties.load(in); + } catch (Exception e) { + log.error("Cannot load property file.", e); + } + + sourceRegistrationApiUrl = properties.getProperty("SOURCE_REGISTRATION_API_URL"); + sourcePublisherApiUrl = properties.getProperty("SOURCE_PUBLISHER_API_URL"); + sourceDevportalApiUrl = properties.getProperty("SOURCE_DEVPORTAL_API_URL"); + sourcePublisherTokenUrl = properties.getProperty("SOURCE_PUBLISHER_TOKEN_URL"); + sourceWso2User = properties.getProperty("SOURCE_WSO2_USER"); + targetRegistrationApiUrl = properties.getProperty("TARGET_REGISTRATION_API_URL"); + targetPublisherApiUrl = properties.getProperty("TARGET_PUBLISHER_API_URL"); + targetDevportalApiUrl = properties.getProperty("TARGET_DEVPORTAL_API_URL"); + targetPublisherTokenUrl = properties.getProperty("TARGET_PUBLISHER_TOKEN_URL"); + targetWso2User = properties.getProperty("TARGET_WSO2_USER"); + truststorePath = properties.getProperty("TRUSTSTORE_PATH"); + truststorePassword = properties.getProperty("TRUSTSTORE_PASSWORD"); + publisherUrlPattern = properties.getProperty("PUBLISHER_URL_PATTERN"); + devportalUrlPattern = properties.getProperty("DEVPORTAL_URL_PATTERN"); + apicurioApiUrl = properties.getProperty("APICURIO_API_URL"); + defaultApiGroup = properties.getProperty("DEFAULT_API_GROUP"); + maxThreads = Integer.parseInt(properties.getProperty("MAX_THREADS", "10")); + + } + + public static synchronized ConfigManager getInstance() { + if (instance == null) { + if (instance == null) { + instance = new ConfigManager(); + } + } + return instance; + } + + public String getSourceRegistrationApiUrl() { + return sourceRegistrationApiUrl; + } + + public String getSourcePublisherApiUrl() { + return sourcePublisherApiUrl; + } + + public String getSourceDevportalApiUrl() { + return sourceDevportalApiUrl; + } + + public String getSourcePublisherTokenUrl() { + return sourcePublisherTokenUrl; + } + + public String getSourceWso2User() { + return sourceWso2User; + } + + public String getTargetRegistrationApiUrl() { + return targetRegistrationApiUrl; + } + + public String getTargetPublisherApiUrl() { + return targetPublisherApiUrl; + } + + public String getTargetDevportalApiUrl() { + return targetDevportalApiUrl; + } + + public String getTargetPublisherTokenUrl() { + return targetPublisherTokenUrl; + } + + public String getTargetWso2User() { + return targetWso2User; + } + + public String getTruststorePath() { + return truststorePath; + } + + public String getTruststorePassword() { + return truststorePassword; + } + + public String getPublisherUrlPattern() { + return publisherUrlPattern; + } + + public String getDevportalUrlPattern() { + return devportalUrlPattern; + } + + public String getApicurioApiUrl() { + return apicurioApiUrl; + } + + public String getDefaultApiGroup() { + return defaultApiGroup; + } + + public int getMaxThreads() { + return maxThreads; + } +} diff --git a/src/main/java/cz/trask/apioperator/model/APIInfo.java b/src/main/java/cz/trask/apioperator/model/APIInfo.java new file mode 100644 index 0000000..08820ab --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/APIInfo.java @@ -0,0 +1,92 @@ +package cz.trask.apioperator.model; + +public class APIInfo { + + private String id; + private String name; + private String description; + private String context; + private String version; + private String provider; + private String lifeCycleStatus; + private String thumbnailUri; + private String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getLifeCycleStatus() { + return lifeCycleStatus; + } + + public void setLifeCycleStatus(String lifeCycleStatus) { + this.lifeCycleStatus = lifeCycleStatus; + } + + public String getThumbnailUri() { + return thumbnailUri; + } + + public void setThumbnailUri(String thumbnailUri) { + this.thumbnailUri = thumbnailUri; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return id + "\t" + name + "\t" + version + "\t" + provider + "\t" + lifeCycleStatus + "\t" + description; + } + +} diff --git a/src/main/java/cz/trask/apioperator/model/APIList.java b/src/main/java/cz/trask/apioperator/model/APIList.java new file mode 100644 index 0000000..7c17de1 --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/APIList.java @@ -0,0 +1,31 @@ +package cz.trask.apioperator.model; + +public class APIList { + + // "count": 102, "next": "", "previous": "", "list": [ + + private int count; + private APIInfo[] list = null; + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public APIInfo[] getList() { + return list; + } + + public void setList(APIInfo[] list) { + this.list = list; + } + + @Override + public String toString() { + return count + "\t" + list; + } + +} diff --git a/src/main/java/cz/trask/apioperator/model/ApiDefinition.java b/src/main/java/cz/trask/apioperator/model/ApiDefinition.java new file mode 100644 index 0000000..1d8c97c --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/ApiDefinition.java @@ -0,0 +1,96 @@ +package cz.trask.apioperator.model; + +import java.util.List; +import java.util.Map; + +public class ApiDefinition { + private String id; + private String name; + private Object description; + private String context; + private String version; + private String provider; + private String apiDefinition; + private Object wsdlUri; + private String lifeCycleStatus; + private boolean isDefaultVersion; + private String type; + private List transport; + private List operations; + private String authorizationHeader; + private List securityScheme; + private List tags; + private List tiers; + private boolean hasThumbnail; + private Map additionalProperties; + private Monetization monetization; + private List ingressURLs; + private List endpointURLs; + private BusinessInformation businessInformation; + private List labels; + private List environmentList; + private List scopes; + private String avgRating; + private AdvertiseInfo advertiseInfo; + private boolean isSubscriptionAvailable; + private List categories; + private List keyManagers; + + // Getters and Setters + + public static class Tier { + private String tierName; + private String tierPlan; + private Object monetizationAttributes; + + // Getters and Setters + } + + public static class EndpointURLs { + private String environmentName; + private String environmentType; + private URLs URLs; + private DefaultVersionURLs defaultVersionURLs; + + public static class URLs { + private String http; + private String https; + private Object ws; + private Object wss; + + // Getters and Setters + } + + public static class DefaultVersionURLs { + private Object http; + private Object https; + private Object ws; + private Object wss; + + // Getters and Setters + } + } + + public static class Monetization { + private boolean enabled; + + // Getters and Setters + } + + public static class BusinessInformation { + private String businessOwner; + private String businessOwnerEmail; + private String technicalOwner; + private String technicalOwnerEmail; + + // Getters and Setters + } + + public static class AdvertiseInfo { + private boolean advertised; + private String originalStoreUrl; + private String apiOwner; + + // Getters and Setters + } +} diff --git a/src/main/java/cz/trask/apioperator/model/EventAPIInfo.java b/src/main/java/cz/trask/apioperator/model/EventAPIInfo.java new file mode 100644 index 0000000..062b2b2 --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/EventAPIInfo.java @@ -0,0 +1,97 @@ +package cz.trask.apioperator.model; + +public class EventAPIInfo { + + String apiName; + String apiId; + String uuid; + String apiVersion; + String apiContext; + String apiProvider; + String apiType; + String apiStatus; + String eventId; + String timeStamp; + String type; + String tenantId; + String tenantDomain; + + public String getApiName() { + return apiName; + } + public void setApiName(String apiName) { + this.apiName = apiName; + } + public String getApiId() { + return apiId; + } + public void setApiId(String apiId) { + this.apiId = apiId; + } + public String getUuid() { + return uuid; + } + public void setUuid(String uuid) { + this.uuid = uuid; + } + public String getApiVersion() { + return apiVersion; + } + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + public String getApiContext() { + return apiContext; + } + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } + public String getApiProvider() { + return apiProvider; + } + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + public String getApiType() { + return apiType; + } + public void setApiType(String apiType) { + this.apiType = apiType; + } + public String getApiStatus() { + return apiStatus; + } + public void setApiStatus(String apiStatus) { + this.apiStatus = apiStatus; + } + public String getEventId() { + return eventId; + } + public void setEventId(String eventId) { + this.eventId = eventId; + } + public String getTimeStamp() { + return timeStamp; + } + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getTenantId() { + return tenantId; + } + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + public String getTenantDomain() { + return tenantDomain; + } + public void setTenantDomain(String tenantDomain) { + this.tenantDomain = tenantDomain; + } +} diff --git a/src/main/java/cz/trask/apioperator/model/FileType.java b/src/main/java/cz/trask/apioperator/model/FileType.java new file mode 100644 index 0000000..fdf4b90 --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/FileType.java @@ -0,0 +1,9 @@ +package cz.trask.apioperator.model; + +public enum FileType { + APIDEF, + OPENAPI, + WSDL, + POLICY, + UNKNOWN +} diff --git a/src/main/java/cz/trask/apioperator/model/HttpResponse.java b/src/main/java/cz/trask/apioperator/model/HttpResponse.java new file mode 100644 index 0000000..ae762ac --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/HttpResponse.java @@ -0,0 +1,49 @@ +package cz.trask.apioperator.model; + +import java.util.List; +import java.util.Map; + +public class HttpResponse { + + String response; + Map> headers; + int responseCode; + byte[] responseBytes; + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public Map> getHeaders() { + return headers; + } + + public void setHeaders(Map> headers) { + this.headers = headers; + } + + public int getResponseCode() { + return responseCode; + } + + public void setResponseCode(int responseCode) { + this.responseCode = responseCode; + } + + public List getResponseHeader(String key) { + return headers.get(key); + } + + public void setResponseBytes(byte[] byteArray) { + responseBytes = byteArray; + } + + public byte[] getResponseBytes() { + return responseBytes; + } + +} diff --git a/src/main/java/cz/trask/apioperator/model/RegisterResponse.java b/src/main/java/cz/trask/apioperator/model/RegisterResponse.java new file mode 100644 index 0000000..aa6ef2f --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/RegisterResponse.java @@ -0,0 +1,62 @@ +package cz.trask.apioperator.model; + +public class RegisterResponse { + + // {"clientId":"QRGgaoQpiRfd6K8KZfU2hZsXoqAa","clientName":"admin_rest_api_publisher","callBackURL":"www.google.lk","clientSecret":"5o_ncm_br0wr8yOXc_ouXOWfOWsa","isSaasApplication":true,"appOwner":"admin","jsonString":"{\"grant_types\":\"password + // refresh_token\",\"redirect_uris\":\"www.google.lk\",\"client_name\":\"admin_rest_api_publisher\"}","jsonAppAttribute":"{}","tokenType":null} + + private String clientId; + private String clientName; + private String callBackURL; + private String clientSecret; + private boolean isSaasApplication; + private String appOwner; + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientName() { + return clientName; + } + + public void setClientName(String clientName) { + this.clientName = clientName; + } + + public String getCallBackURL() { + return callBackURL; + } + + public void setCallBackURL(String callBackURL) { + this.callBackURL = callBackURL; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public boolean isSaasApplication() { + return isSaasApplication; + } + + public void setSaasApplication(boolean isSaasApplication) { + this.isSaasApplication = isSaasApplication; + } + + public String getAppOwner() { + return appOwner; + } + + public void setAppOwner(String appOwner) { + this.appOwner = appOwner; + } +} diff --git a/src/main/java/cz/trask/apioperator/model/StartParameters.java b/src/main/java/cz/trask/apioperator/model/StartParameters.java new file mode 100644 index 0000000..caa065e --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/StartParameters.java @@ -0,0 +1,35 @@ +package cz.trask.apioperator.model; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class StartParameters { + + private static Logger log = LogManager.getLogger(StartParameters.class); + + String command; + + public String getCommand() { + return command; + } + + public void setCommand(String command) { + this.command = command; + } + + public static StartParameters parse(String commandLine) throws Exception { + StartParameters res = new StartParameters(); + + try { + String[] rawParams = commandLine.split("-"); + res.setCommand(rawParams[0]); + + } catch (Exception e) { + log.error("Error while parsing startup parameters.", e); + throw e; + } + + return res; + } + +} diff --git a/src/main/java/cz/trask/apioperator/model/TokenResponse.java b/src/main/java/cz/trask/apioperator/model/TokenResponse.java new file mode 100644 index 0000000..3a8a65c --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/TokenResponse.java @@ -0,0 +1,53 @@ +package cz.trask.apioperator.model; + +public class TokenResponse { + + // {"access_token":"6be1aa81-d0ae-321e-9e3e-2ea89dd9f847","refresh_token":"5cff194d-cb16-3dc2-ab60-3c44ba25ae4a","scope":"apim:api_view","token_type":"Bearer","expires_in":3600} + + private String access_token; + private String refresh_token; + private String scope; + private String token_type; + private long expires_in; + + public String getAccess_token() { + return access_token; + } + + public void setAccess_token(String access_token) { + this.access_token = access_token; + } + + public String getRefresh_token() { + return refresh_token; + } + + public void setRefresh_token(String refresh_token) { + this.refresh_token = refresh_token; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getToken_type() { + return token_type; + } + + public void setToken_type(String token_type) { + this.token_type = token_type; + } + + public long getExpires_in() { + return expires_in; + } + + public void setExpires_in(long expires_in) { + this.expires_in = expires_in; + } + +} diff --git a/src/main/java/cz/trask/apioperator/model/ZipEntryData.java b/src/main/java/cz/trask/apioperator/model/ZipEntryData.java new file mode 100644 index 0000000..3eccc0e --- /dev/null +++ b/src/main/java/cz/trask/apioperator/model/ZipEntryData.java @@ -0,0 +1,43 @@ +package cz.trask.apioperator.model; + +public class ZipEntryData { + private String name; + private FileType type; + private byte[] content; + + public ZipEntryData(String name, FileType type, byte[] content) { + this.name = name; + this.type = type; + this.content = content; + } + + // Gettery a settery + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public FileType getType() { + return type; + } + + public void setType(FileType type) { + this.type = type; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + + @Override + public String toString() { + return "ZipEntryData{name='" + name + "', type=" + type + "}"; + } +} diff --git a/src/main/java/cz/trask/apioperator/utils/ZipExtractor.java b/src/main/java/cz/trask/apioperator/utils/ZipExtractor.java new file mode 100644 index 0000000..f119156 --- /dev/null +++ b/src/main/java/cz/trask/apioperator/utils/ZipExtractor.java @@ -0,0 +1,66 @@ +package cz.trask.apioperator.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import cz.trask.apioperator.model.FileType; +import cz.trask.apioperator.model.ZipEntryData; + +public class ZipExtractor { + + public static List extractFilesFromZip(byte[] data) throws IOException { + List fileList = new ArrayList<>(); + + try (ByteArrayInputStream fis = new ByteArrayInputStream(data); ZipInputStream zis = new ZipInputStream(fis)) { + + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + // Ignoruj adresáře + if (!entry.isDirectory()) { + String name = entry.getName().substring(entry.getName().lastIndexOf('/') + 1); + FileType type = determineFileType(entry.getName()); + byte[] content = readAllBytes(zis); + + fileList.add(new ZipEntryData(name, type, content)); + } + zis.closeEntry(); + } + } + + return fileList; + } + + private static FileType determineFileType(String fileName) { + String lowerFileName = fileName.toLowerCase(); + if (lowerFileName.endsWith("api.yaml")) { + return FileType.APIDEF; + } else if (lowerFileName.contains("/definitions/swagger.yaml")) { + return FileType.OPENAPI; + } else if (lowerFileName.endsWith(".wsdl")) { + return FileType.WSDL; + } else if (lowerFileName.contains("/policies/")) { + return FileType.POLICY; + } + return FileType.UNKNOWN; + } + + private static boolean isWsdLFile(String fileName) { + return fileName.toLowerCase().endsWith(".wsdl"); + } + + private static byte[] readAllBytes(ZipInputStream zis) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = zis.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + buffer.flush(); + return buffer.toByteArray(); + } +} diff --git a/src/main/resources/api-operator.properties b/src/main/resources/api-operator.properties new file mode 100644 index 0000000..d33805b --- /dev/null +++ b/src/main/resources/api-operator.properties @@ -0,0 +1,23 @@ +SOURCE_REGISTRATION_API_URL = https://localhost:9443/client-registration/v0.17/register +SOURCE_PUBLISHER_API_URL = https://localhost:9443/api/am/publisher +SOURCE_DEVPORTAL_API_URL = https://localhost:9443/api/am/devportal +SOURCE_PUBLISHER_TOKEN_URL = https://localhost:9443/oauth2/token +SOURCE_WSO2_USER = YWRtaW46YWRtaW4= + +TARGET_REGISTRATION_API_URL = https://localhost:9443/client-registration/v0.17/register +TARGET_PUBLISHER_API_URL = https://localhost:9443/api/am/publisher +TARGET_DEVPORTAL_API_URL = https://localhost:9443/api/am/devportal +TARGET_PUBLISHER_TOKEN_URL = https://localhost:9443/oauth2/token +TARGET_WSO2_USER = YWRtaW46YWRtaW4= + +TRUSTSTORE_PATH = client-truststore.jks +TRUSTSTORE_PASSWORD = wso2carbon + +PUBLISHER_URL_PATTERN = https://api-developers.dev.koop.appl.services/publisher/apis/{API_ID}/overview +DEVPORTAL_URL_PATTERN = https://api-developers.dev.koop.appl.services/devportal/apis/{API_ID}/overview + +#APICURIO_API_URL = http://10.0.0.190:8080/apis/registry/v2 +APICURIO_API_URL = http://apicurio:8095/apis/registry/v2 +DEFAULT_API_GROUP = api + +MAX_THREADS = 1 \ No newline at end of file diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties new file mode 100644 index 0000000..e2c56a7 --- /dev/null +++ b/src/main/resources/log4j2.properties @@ -0,0 +1,28 @@ +rootLogger.level = info +rootLogger.appenderRefs = console, rolling +rootLogger.appenderRef.stdout.ref = STDOUT +rootLogger.appenderRef.file.ref = RollingFileAppender + +logger.cz-trask.name=cz.trask +logger.cz-trask.level = debug +logger.cz-trask.additivity=false +logger.cz-trask.appenderRefs = rolling, console +logger.cz-trask.appenderRef.file.ref = RollingFileAppender +logger.cz-trask.appenderRef.stdout.ref = STDOUT + +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d [%t] %-5level %logger{36} - %msg%n + +appender.rolling.type = RollingFile +appender.rolling.name = RollingFileAppender +appender.rolling.fileName = api-operator.log +appender.rolling.filePattern = api-operator-%d{yyyy-MM-dd}.%i.log +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = %d [%t] %-5level %logger{36} - %msg%n +appender.rolling.policies.type = Policies +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size = 50MB +appender.rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.rolling.policies.time.interval = 1