UniqueInterfaceGenerator.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- package org.openspcoop2.utils.openapi;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import org.apache.logging.log4j.Level;
- import org.openspcoop2.utils.LoggerWrapperFactory;
- import org.openspcoop2.utils.json.JSONUtils;
- import org.openspcoop2.utils.json.JsonPathExpressionEngine;
- import org.openspcoop2.utils.json.YAMLUtils;
- import org.openspcoop2.utils.resources.FileSystemUtilities;
- import org.openspcoop2.utils.rest.ApiFormats;
- import org.slf4j.Logger;
- import com.fasterxml.jackson.databind.JsonNode;
- import io.swagger.v3.oas.models.Components;
- import io.swagger.v3.oas.models.OpenAPI;
- import io.swagger.v3.oas.models.callbacks.Callback;
- import io.swagger.v3.oas.models.examples.Example;
- import io.swagger.v3.oas.models.headers.Header;
- import io.swagger.v3.oas.models.links.Link;
- import io.swagger.v3.oas.models.media.Schema;
- import io.swagger.v3.oas.models.parameters.Parameter;
- import io.swagger.v3.oas.models.parameters.RequestBody;
- import io.swagger.v3.oas.models.responses.ApiResponse;
- import io.swagger.v3.oas.models.security.SecurityScheme;
- import io.swagger.v3.parser.OpenAPIV3Parser;
- import io.swagger.v3.parser.converter.SwaggerConverter;
- import io.swagger.v3.parser.core.models.ParseOptions;
- import io.swagger.v3.parser.core.models.SwaggerParseResult;
- /**
- * UniqueInterfaceGenerator
- *
- * @author Andrea Poli (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class UniqueInterfaceGenerator {
- public static void main(String[] args) throws Exception {
-
- LoggerWrapperFactory.setDefaultConsoleLogConfiguration(Level.ERROR);
-
- if(args==null || args.length<4) {
- throw new Exception("Use: UniqueInterfaceGenerator <versioneOpenAPI> <destFile> <master> <attachmentsDir>");
- }
-
- String tipo = args[0].trim();
- ApiFormats format = ApiFormats.valueOf(tipo);
-
- String fileDest = args[1].trim();
-
- UniqueInterfaceGeneratorConfig config = new UniqueInterfaceGeneratorConfig();
- config.format = format;
- String fileMaster = args[2].trim();
- config.master = FileSystemUtilities.readFile(fileMaster);
- File fMaster = new File(fileMaster);
- String ext = null;
- try{
- ext = fileMaster.substring(fileMaster.lastIndexOf(".")+1,fileMaster.length());
- }catch(Exception e){
- // ext undefined
- }
- config.yaml = "yaml".equalsIgnoreCase(ext);
- HashMap<String,String> attachments = new HashMap<>();
- File fDir = new File(args[3].trim());
- if(fDir.isDirectory()==false) {
- throw new Exception("attachmentsDir ["+fDir.getAbsolutePath()+"] is not directory");
- }
- File[] files = fDir.listFiles();
- if(files!=null) {
- for (int j = 0; j < files.length; j++) {
- if(files[j].getName().equals(fMaster.getName())) {
- continue;
- }
- if(files[j].isDirectory()) {
- continue;
- }
- //System.out.println("READ ["+files[j]+"] ... ");
- attachments.put(files[j].getName(), FileSystemUtilities.readFile(files[j]));
- //System.out.println("READ ["+files[j]+"] ok");
- }
- }
- config.attachments = attachments;
-
- List<String> blackListParameters = null;
- List<String> blackListComponents = null;
- if(args.length>5) {
-
- String blackListParametersArgs = args[4].trim();
- if(blackListParametersArgs!=null) {
- blackListParameters = new ArrayList<>();
- if(blackListParametersArgs.contains(",")) {
- String [] tmp = blackListParametersArgs.split(",");
- for (String s : tmp) {
- blackListParameters.add(s);
- }
- }else {
- blackListParameters.add(blackListParametersArgs);
- }
- }
-
- String blackListComponentsArgs = args[5].trim();
- if(blackListComponentsArgs!=null) {
- blackListComponents = new ArrayList<>();
- if(blackListComponentsArgs.contains(",")) {
- String [] tmp = blackListComponentsArgs.split(",");
- for (String s : tmp) {
- blackListComponents.add(s);
- }
- }else {
- blackListComponents.add(blackListComponentsArgs);
- }
- }
-
- }
-
- generate(fileDest, config, blackListParameters, blackListComponents, true, null);
- }
- private static void debug(boolean debug, Logger log, String msg) {
- if(debug) {
- if(log!=null) {
- log.debug(msg);
- }
- else {
- System.out.println(msg);
- }
- }
- }
-
- public static void generate(String fileDest, UniqueInterfaceGeneratorConfig config,
- List<String> blackListParameters, List<String> blackListComponents,
- boolean debug, Logger log) throws Exception {
- String schemaRebuild = generate(config, blackListParameters, blackListComponents, debug, log);
- try(FileOutputStream fout = new FileOutputStream(fileDest)){
- fout.write(schemaRebuild.getBytes());
- fout.flush();
- }
- }
- public static String generate(UniqueInterfaceGeneratorConfig config,
- List<String> blackListParameters, List<String> blackListComponents,
- boolean debug, Logger log) throws Exception {
-
- SwaggerParseResult pr = null;
- ParseOptions parseOptions = new ParseOptions();
-
- if(ApiFormats.SWAGGER_2.equals(config.format)) {
- pr = new SwaggerConverter().readContents(config.master, null, parseOptions);
- }
- else {
- pr = new OpenAPIV3Parser().readContents(config.master, null, parseOptions);
- }
- StringBuilder sbParseWarningResult = new StringBuilder();
- OpenAPI api = AbstractOpenapiApiReader.parseResult(LoggerWrapperFactory.getLogger(UniqueInterfaceGenerator.class), pr, sbParseWarningResult);
- if(api.getComponents()==null) {
- api.setComponents(new Components());
- }
-
- Map<String,String> attachments = config.attachments;
- Iterator<String> attachmentNames = attachments.keySet().iterator();
- while (attachmentNames.hasNext()) {
- String attachName = (String) attachmentNames.next();
- String attach = attachments.get(attachName);
-
- debug(debug,log,"Merge ["+attachName+"] ...");
- if(ApiFormats.SWAGGER_2.equals(config.format)) {
- pr = new SwaggerConverter().readContents(attach, null, parseOptions);
- }
- else {
- pr = new OpenAPIV3Parser().readContents(attach, null, parseOptions);
- }
- OpenAPI apiInternal = AbstractOpenapiApiReader.parseResult(LoggerWrapperFactory.getLogger(UniqueInterfaceGenerator.class), pr, sbParseWarningResult);
- if(apiInternal.getComponents()!=null) {
- if(apiInternal.getComponents().getCallbacks()!=null) {
- Map<String, Callback> maps = apiInternal.getComponents().getCallbacks();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Callback value = maps.get(key);
- api.getComponents().addCallbacks(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" callback");
- }
- if(apiInternal.getComponents().getExamples()!=null) {
- Map<String, Example> maps = apiInternal.getComponents().getExamples();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Example value = maps.get(key);
- api.getComponents().addExamples(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" example");
- }
- if(apiInternal.getComponents().getExtensions()!=null) {
- Map<String, Object> maps = apiInternal.getComponents().getExtensions();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Object value = maps.get(key);
- api.getComponents().addExtension(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" extensions");
- }
- if(apiInternal.getComponents().getHeaders()!=null) {
- Map<String, Header> maps = apiInternal.getComponents().getHeaders();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Header value = maps.get(key);
- api.getComponents().addHeaders(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" header");
- }
- if(apiInternal.getComponents().getLinks()!=null) {
- Map<String, Link> maps = apiInternal.getComponents().getLinks();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Link value = maps.get(key);
- api.getComponents().addLinks(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" link");
- }
- if(apiInternal.getComponents().getParameters()!=null) {
- Map<String, Parameter> maps = apiInternal.getComponents().getParameters();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- if(blackListParameters!=null && blackListParameters.contains(key)) {
- debug(debug,log,"Parameter '"+key+"' skipped");
- continue;
- }
- Parameter value = maps.get(key);
- api.getComponents().addParameters(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" parameter");
- }
- if(apiInternal.getComponents().getRequestBodies()!=null) {
- Map<String, RequestBody> maps = apiInternal.getComponents().getRequestBodies();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- RequestBody value = maps.get(key);
- api.getComponents().addRequestBodies(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" requestBody");
- }
- if(apiInternal.getComponents().getResponses()!=null) {
- Map<String, ApiResponse> maps = apiInternal.getComponents().getResponses();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- ApiResponse value = maps.get(key);
- api.getComponents().addResponses(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+"] response");
- }
- if(apiInternal.getComponents().getSchemas()!=null) {
- @SuppressWarnings("rawtypes")
- Map<String, Schema> maps = apiInternal.getComponents().getSchemas();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- if(blackListComponents!=null && blackListComponents.contains(key)) {
- debug(debug,log,"Component '"+key+"' skipped");
- continue;
- }
- Schema<?> value = maps.get(key);
- api.getComponents().addSchemas(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" schema");
- }
- if(apiInternal.getComponents().getSecuritySchemes()!=null) {
- Map<String, SecurityScheme> maps = apiInternal.getComponents().getSecuritySchemes();
- int mapsSize = 0;
- if(maps!=null && !maps.isEmpty()) {
- mapsSize = maps.size();
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- SecurityScheme value = maps.get(key);
- api.getComponents().addSecuritySchemes(key, value);
- }
- }
- debug(debug,log,"\t"+mapsSize+" security schema");
- }
- }
- debug(debug,log,"Merge ["+attachName+"] ok");
- }
-
- // clean attributi non permessi in swagger editor
- api.setExtensions(null);
- api.getComponents().setExtensions(null);
- if(api.getComponents().getHeaders()!=null) {
- Map<String, Header> maps = api.getComponents().getHeaders();
- if(maps!=null && !maps.isEmpty()) {
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Header value = maps.get(key);
- value.setExplode(null);
- value.setStyle(null);
- }
- }
- }
- if(api.getComponents().getParameters()!=null) {
- Map<String, Parameter> maps = api.getComponents().getParameters();
- if(maps!=null && !maps.isEmpty()) {
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Parameter value = maps.get(key);
- value.setExplode(null);
- value.setStyle(null);
- //debug(debug,log,"PARAMETRO *"+key+"* ["+value.getName()+"] ["+value.getExample()+"] ["+value.getExamples()+"] ref["+value.get$ref()+"] tipo["+value.getClass().getName()+"]");
- checkSchema(0,("Parameter-"+key), value.getSchema());
- }
- }
- }
- if(api.getComponents().getSchemas()!=null) {
- @SuppressWarnings("rawtypes")
- Map<String, Schema> maps = api.getComponents().getSchemas();
- if(maps!=null && !maps.isEmpty()) {
- Iterator<String> keys = maps.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Schema<?> value = maps.get(key);
- String sorgente = "";
- if(value.getName()!=null) {
- sorgente = sorgente + value.getName();
- }
- else {
- sorgente = sorgente + "RootSchema";
- }
- checkSchema(0, sorgente, value);
- }
- }
- }
-
- JsonNode jsonNode = null;
- String s = null;
- if(config.yaml) {
- s = YAMLUtils.getObjectWriter().writeValueAsString(api);
- jsonNode = YAMLUtils.getInstance().getAsNode(s);
- }
- else {
- s = JSONUtils.getObjectWriter().writeValueAsString(api);
- jsonNode = JSONUtils.getInstance().getAsNode(s);
- }
-
- JsonPathExpressionEngine engine = new JsonPathExpressionEngine();
- List<String> refPath = engine.getStringMatchPattern(jsonNode, "$..$ref");
- String schemaRebuild = s;
-
- // Faccio due passate, prima con i caratteri " e ' in modo da risolvere le ref precisamente,
- // poiche' l'algoritmo e' soggetto a problemi quando ci sono nomi inclusi in altri ref. Es.:
- // test.yaml#...
- // http://test/test.yaml#....
- schemaRebuild = replace(refPath, schemaRebuild, true);
- schemaRebuild = replace(refPath, schemaRebuild, false);
-
- /*
- Object oDescr = engine.getMatchPattern(jsonNode, "$.info.description", JsonPathReturnType.NODE);
- if(oDescr!=null) {
- String descr = null;
- if(oDescr instanceof List<?>) {
- @SuppressWarnings("unchecked")
- List<String> l = (List<String>) oDescr;
- if(!l.isEmpty()) {
- descr = l.get(0);
- }
- }
- else if(oDescr instanceof String) {
- descr = (String) oDescr;
- }
- else if(oDescr instanceof JsonNode) {
- JsonNode jN = (JsonNode) oDescr;
- descr = jN.asText();
- }
- else {
- debug(debug,log,"Description type unknown ["+oDescr.getClass().getName()+"]");
- }
- if(descr!=null && org.apache.commons.lang.StringUtils.isNotEmpty(descr)) {
- schemaRebuild = schemaRebuild.replace("info:", "info:\n x-summary: \""+descr+"\"");
- }
- }
- */
-
- if(schemaRebuild.startsWith("---")) {
- schemaRebuild = schemaRebuild.substring("---".length());
- }
- if(schemaRebuild.startsWith("\n")) {
- schemaRebuild = schemaRebuild.substring("\n".length());
- }
-
- String extensions = "extensions:\n" +" ";
- schemaRebuild = schemaRebuild.replace(extensions, "");
- String ext = " x-";
- String extCorrect = " x-";
- while(schemaRebuild.contains(ext)) {
- schemaRebuild = schemaRebuild.replace(ext, extCorrect);
- }
-
- return schemaRebuild;
-
- }
- private static String replace(List<String> refPath, String schemaRebuild, boolean usePrefixChar) {
- if(refPath!=null && !refPath.isEmpty()) {
- for (String ref : refPath) {
-
- //System.out.println("...............ANALIZZO REF ["+ref+"]");
-
- if(schemaRebuild.contains(ref)) {
-
- //System.out.println(" PROCESS ["+ref+"]");
-
- if(ref.startsWith("#")==false) {
-
- //System.out.println(" PROCESS INTERNAL ["+ref+"]");
-
- String destra = ref.substring(ref.indexOf("#"));
- String refForReplace = ref;
-
- //System.out.println("destra ["+destra+"]");
- //System.out.println("destra ["+refForReplace+"]");
-
- if(usePrefixChar) {
- String rep = "\""+refForReplace+"\"";
- String destraRep = "\""+destra+"\"";
- while(schemaRebuild.contains(rep)) {
- schemaRebuild = schemaRebuild.replace(rep, destraRep);
- }
- rep = "'"+refForReplace+"'";
- destraRep = "'"+destra+"'";
- while(schemaRebuild.contains(rep)) {
- schemaRebuild = schemaRebuild.replace(rep, destraRep);
- }
- }
- else {
- while(schemaRebuild.contains(refForReplace)) {
- schemaRebuild = schemaRebuild.replace(refForReplace, destra);
- }
- }
-
- if(refForReplace.startsWith("./") && refForReplace.length()>2) {
-
- //System.out.println("CASO SPECIALE!");
-
- refForReplace = refForReplace.substring(2);
-
- if(usePrefixChar) {
- String rep = "\""+refForReplace+"\"";
- String destraRep = "\""+destra+"\"";
- while(schemaRebuild.contains(rep)) {
- schemaRebuild = schemaRebuild.replace(rep, destraRep);
- }
- rep = "'"+refForReplace+"'";
- destraRep = "'"+destra+"'";
- while(schemaRebuild.contains(rep)) {
- schemaRebuild = schemaRebuild.replace(rep, destraRep);
- }
- }
- else {
- while(schemaRebuild.contains(refForReplace)) {
- schemaRebuild = schemaRebuild.replace(refForReplace, destra);
- }
- }
- }
-
- }
- }
- }
- }
- return schemaRebuild;
- }
-
- private static int checkSchema(int profondita, String sorgente, Schema<?> schema) {
-
- if(profondita>1000) {
- return profondita; // evitare stack overflow
- }
-
- @SuppressWarnings("rawtypes")
- Map<String, Schema> properties = schema.getProperties();
- if(properties!=null && !properties.isEmpty()) {
- for (String key : properties.keySet()) {
- Schema<?> value = properties.get(key);
- String sorgenteInterno = sorgente+".";
- if(value.getName()!=null) {
- sorgenteInterno = sorgenteInterno + value.getName();
- }
- else {
- sorgenteInterno = sorgenteInterno + "schemaProfondita"+profondita;
- }
- //debug(debug,log,"SCHEMA ("+sorgente+") *"+key+"* ["+value.getName()+"] ["+value.getType()+"] ["+value.getFormat()+"] ["+value.getExample()+"] ref["+value.get$ref()+"] schema["+value.getClass().getName()+"]");
- @SuppressWarnings("unused")
- int p = checkSchema((profondita+1),sorgenteInterno,value);
- }
- }
-
- return profondita;
- }
-
- }