AbstractOpenapiApiReader.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 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.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.json.YAMLUtils;
import org.openspcoop2.utils.resources.Charset;
import org.openspcoop2.utils.resources.FileSystemUtilities;
import org.openspcoop2.utils.rest.ApiFormats;
import org.openspcoop2.utils.rest.ApiReaderConfig;
import org.openspcoop2.utils.rest.IApiReader;
import org.openspcoop2.utils.rest.ProcessingException;
import org.openspcoop2.utils.rest.api.AbstractApiParameter;
import org.openspcoop2.utils.rest.api.Api;
import org.openspcoop2.utils.rest.api.ApiBodyParameter;
import org.openspcoop2.utils.rest.api.ApiCookieParameter;
import org.openspcoop2.utils.rest.api.ApiHeaderParameter;
import org.openspcoop2.utils.rest.api.ApiOperation;
import org.openspcoop2.utils.rest.api.ApiParameterSchema;
import org.openspcoop2.utils.rest.api.ApiParameterSchemaComplexType;
import org.openspcoop2.utils.rest.api.ApiReference;
import org.openspcoop2.utils.rest.api.ApiRequest;
import org.openspcoop2.utils.rest.api.ApiRequestDynamicPathParameter;
import org.openspcoop2.utils.rest.api.ApiRequestFormParameter;
import org.openspcoop2.utils.rest.api.ApiRequestQueryParameter;
import org.openspcoop2.utils.rest.api.ApiResponse;
import org.openspcoop2.utils.rest.api.ApiSchema;
import org.openspcoop2.utils.rest.api.ApiSchemaTypeRestriction;
import org.openspcoop2.utils.transport.http.HttpRequestMethod;
import org.slf4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.CookieParameter;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.PathParameter;
import io.swagger.v3.oas.models.parameters.QueryParameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
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;
/**
* AbstractOpenapiApiReader
*
* @author Andrea Poli (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*
*/
public abstract class AbstractOpenapiApiReader implements IApiReader {
private OpenAPI openApi;
private String openApiRaw;
private ApiFormats format;
private ParseOptions parseOptions;
private List<ApiSchema> schemas;
private boolean resolveExternalRef = true;
private String parseWarningResult;
private boolean debug;
public void setDebug(boolean debug) {
this.debug = debug;
}
public AbstractOpenapiApiReader(ApiFormats format) {
this.format = format;
this.parseOptions = new ParseOptions();
this.schemas = new ArrayList<>();
}
protected static OpenAPI parseResult(Logger log, SwaggerParseResult pr, StringBuilder sbParseWarningResult) throws ProcessingException {
if(pr==null) {
throw new ProcessingException("Parse result undefined");
}
StringBuilder bfMessage = new StringBuilder();
if(pr.getMessages()!=null && pr.getMessages().size()>0) {
for (String msg : pr.getMessages()) {
if(bfMessage.length()>0) {
bfMessage.append("\n");
}
bfMessage.append("- ").append(msg);
}
}
OpenAPI openApi = null;
if(pr.getOpenAPI()!=null) {
openApi = pr.getOpenAPI();
if(bfMessage.length()>0) {
log.debug(bfMessage.toString());
sbParseWarningResult.append(bfMessage.toString());
}
}
else {
if(bfMessage.length()>0) {
throw new ProcessingException("Parse failed: "+bfMessage.toString());
}
else {
throw new ProcessingException("Parse failed");
}
}
return openApi;
}
@Override
public void init(Logger log, String content, ApiReaderConfig config) throws ProcessingException {
this._init(log, content, config);
}
@Override
public void init(Logger log, String content, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
this._init(log, content, config, schema);
}
private void _init(Logger log, String contentParam, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
String content = contentParam;
try {
YAMLUtils yamlUtils = YAMLUtils.getInstance();
boolean apiRawIsYaml = yamlUtils.isYaml(content);
if(apiRawIsYaml) {
// Fix merge key '<<: *'
if(YAMLUtils.containsMergeKeyAnchor(content)) {
// Risoluzione merge key '<<: *'
String jsonRepresentation = YAMLUtils.resolveMergeKeyAndConvertToJson(content);
if(jsonRepresentation!=null) {
content = jsonRepresentation;
}
}
}
}catch(Throwable t) {
log.error("Find and resolve merge key failed: "+t.getMessage(),t);
content = contentParam;
}
try {
SwaggerParseResult pr = null;
if(ApiFormats.SWAGGER_2.equals(this.format)) {
pr = new SwaggerConverter().readContents(content, null, this.parseOptions);
}
else {
pr = new OpenAPIV3Parser().readContents(content, null, this.parseOptions);
}
StringBuilder sbParseWarningResult = new StringBuilder();
this.openApi = parseResult(log, pr, sbParseWarningResult);
if(sbParseWarningResult.length()>0) {
this.parseWarningResult = sbParseWarningResult.toString();
}
this.openApiRaw = content;
if(schema!=null && schema.length>0) {
for (int i = 0; i < schema.length; i++) {
this.schemas.add(schema[i]);
}
}
this.resolveExternalRef = config.isProcessInclude();
} catch(Exception e) {
throw new ProcessingException(e);
}
}
@Override
public void init(Logger log, byte[] content, ApiReaderConfig config) throws ProcessingException {
this._init(log, content, config);
}
@Override
public void init(Logger log, byte[] content, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
this._init(log, content, config, schema);
}
private void _init(Logger log, byte[] content, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
String s = null;
try {
String charset = config!=null?config.getCharset().getValue():Charset.UTF_8.getValue();
s = new String(content,charset);
} catch(Exception e) {
throw new ProcessingException(e);
}
this._init(log, s, config, schema);
}
@Override
public void init(Logger log, File file, ApiReaderConfig config) throws ProcessingException {
this._init(log, file, config);
}
@Override
public void init(Logger log, File file, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
this._init(log, file, config, schema);
}
private void _init(Logger log, File file, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
byte[]c = null;
try {
c = FileSystemUtilities.readBytesFromFile(file);
} catch(Exception e) {
throw new ProcessingException(e);
}
this._init(log, c, config, schema);
}
@Override
public void init(Logger log, URI uri, ApiReaderConfig config) throws ProcessingException {
this._init(log, uri, config);
}
@Override
public void init(Logger log, URI uri, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
this._init(log, uri, config, schema);
}
private void _init(Logger log, URI uri, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
byte[]c = null;
try {
c = Utilities.getAsByteArray(uri.toURL().openStream());
} catch(Exception e) {
throw new ProcessingException(e);
}
this._init(log, c, config, schema);
}
@Override
public void init(Logger log, Document doc, ApiReaderConfig config) throws ProcessingException {
this._init(log, doc, config);
}
@Override
public void init(Logger log, Document doc, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
this._init(log, doc, config, schema);
}
private void _init(Logger log, Document doc, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
throw new ProcessingException("Not implemented");
}
@Override
public void init(Logger log, Element element, ApiReaderConfig config) throws ProcessingException {
this._init(log, element, config);
}
@Override
public void init(Logger log, Element element, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
this._init(log, element, config, schema);
}
private void _init(Logger log, Element element, ApiReaderConfig config, ApiSchema ... schema) throws ProcessingException {
throw new ProcessingException("Not implemented");
}
@Override
public Api read() throws ProcessingException {
if(this.openApi == null)
throw new ProcessingException("Api non correttamente inizializzata");
try {
OpenapiApi api = new OpenapiApi(this.format, this.openApi, this.openApiRaw, this.parseWarningResult);
if(!this.schemas.isEmpty()) {
for (ApiSchema apiSchema : this.schemas) {
api.addSchema(apiSchema);
}
}
if(!this.openApi.getServers().isEmpty()) {
String server = this.openApi.getServers().get(0).getUrl();
URL url = null;
try {
url = new URL(server);
}catch(Exception e) {
// provo a verificare se il problema รจ che non e' stato definito il protocollo (es. in swagger lo 'schemes')
if(server!=null && server.startsWith("/")) {
if(!server.equals("/")) {
server = "http:"+server;
try {
url = new URL(server);
}catch(Exception e2) {
// nop
}
}
}
}
if(url!=null) {
api.setBaseURL(url);
}
}
if(this.openApi.getInfo()!=null) {
api.setDescription(this.openApi.getInfo().getDescription());
}
if(this.openApi.getPaths() != null){
for (String pathK : this.openApi.getPaths().keySet()) {
PathItem path = this.openApi.getPaths().get(pathK);
if(path.getGet() != null) {
ApiOperation operation = getOperation(path.getGet(), path.getParameters(), HttpRequestMethod.GET, pathK, api);
api.addOperation(operation);
}
if(path.getHead() != null) {
ApiOperation operation = getOperation(path.getHead(), path.getParameters(), HttpRequestMethod.HEAD, pathK, api);
api.addOperation(operation);
}
if(path.getPost() != null) {
ApiOperation operation = getOperation(path.getPost(), path.getParameters(), HttpRequestMethod.POST, pathK, api);
api.addOperation(operation);
}
if(path.getPut() != null) {
ApiOperation operation = getOperation(path.getPut(), path.getParameters(), HttpRequestMethod.PUT, pathK, api);
api.addOperation(operation);
}
if(path.getDelete() != null) {
ApiOperation operation = getOperation(path.getDelete(), path.getParameters(), HttpRequestMethod.DELETE, pathK, api);
api.addOperation(operation);
}
if(path.getOptions() != null) {
ApiOperation operation = getOperation(path.getOptions(), path.getParameters(), HttpRequestMethod.OPTIONS, pathK, api);
api.addOperation(operation);
}
if(path.getTrace() != null) {
ApiOperation operation = getOperation(path.getTrace(), path.getParameters(), HttpRequestMethod.TRACE, pathK, api);
api.addOperation(operation);
}
if(path.getPatch() != null) {
ApiOperation operation = getOperation(path.getPatch(), path.getParameters(), HttpRequestMethod.PATCH, pathK, api);
api.addOperation(operation);
}
}
}
return api;
} catch(Exception e){
throw new ProcessingException(e);
}
}
private ApiOperation getOperation(Operation operation, List<Parameter> listParameter, HttpRequestMethod method, String pathK, OpenapiApi api) {
ApiOperation apiOperation = new ApiOperation(method, pathK);
apiOperation.setDescription(operation.getDescription());
if( (listParameter!=null && !listParameter.isEmpty())
||
(operation.getParameters() != null)
||
(operation.getRequestBody() != null)
) {
ApiRequest request = new ApiRequest();
if(listParameter!=null && !listParameter.isEmpty()) {
for(Parameter param: listParameter) {
addRequestParameter(param, request, method, pathK, api);
}
}
if(operation.getParameters() != null) {
for(Parameter param: operation.getParameters()) {
addRequestParameter(param, request, method, pathK, api);
}
}
if(operation.getRequestBody() != null) {
List<ApiBodyParameter> lst = createRequestBody(operation.getRequestBody(), method, pathK, api);
for(ApiBodyParameter param: lst) {
request.addBodyParameter(param);
}
}
apiOperation.setRequest(request);
}
if(operation.getResponses()!= null && !operation.getResponses().isEmpty()) {
List<ApiResponse> responses = new ArrayList<ApiResponse>();
for(String responseK: operation.getResponses().keySet()) {
responses.add(createResponses(responseK, operation.getResponses().get(responseK), method, pathK, api));
}
apiOperation.setResponses(responses);
}
return apiOperation;
}
private List<ApiBodyParameter> createRequestBody(RequestBody requestBody, HttpRequestMethod method, String path, OpenapiApi api) {
if(requestBody.get$ref()!=null) {
String ref = requestBody.get$ref();
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
ref = ref.trim().replaceAll("#/components/requestBodies/", "").replaceAll("#/definitions/", "");
if(api.getApi()==null) {
throw new RuntimeException("Richiesta non corretta: api da cui risolvere la ref '"+requestBody.get$ref()+"' non trovata");
}
if(api.getApi().getComponents()==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Richiesta non corretta: componenti, sui cui risolvere la ref '"+requestBody.get$ref()+"', non presenti");
}
}
else {
if(api.getApi().getComponents().getResponses()==null || api.getApi().getComponents().getResponses().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Richiesta non corretta: richieste definite come componenti, sui cui risolvere la ref '"+requestBody.get$ref()+"', non presenti");
}
}
else {
boolean find = false;
Iterator<String> itKeys = api.getApi().getComponents().getRequestBodies().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(ref)) {
requestBody = api.getApi().getComponents().getRequestBodies().get(key);
find = true;
break;
}
}
if(!find) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Richiesta non corretta: ref '"+requestBody.get$ref()+"' non presente tra le richieste definite come componenti");
}
}
}
}
}
List<ApiBodyParameter> lst = new ArrayList<ApiBodyParameter>();
if(requestBody.getContent() != null && !requestBody.getContent().isEmpty()) {
for(String consume: requestBody.getContent().keySet()) {
Schema<?> model = requestBody.getContent().get(consume).getSchema();
String type = null;
ApiReference apiRef = null;
if(model.get$ref()!= null) {
String href = model.get$ref().trim();
if(href.contains("#") && !href.startsWith("#")) {
type = href.substring(href.indexOf("#"), href.length());
type = type.replaceAll("#/components/schemas/", "").replaceAll("#/definitions/", "");
String ref = href.split("#")[0];
File fRef = new File(ref);
apiRef = new ApiReference(fRef.getName(), type);
}
else {
type = href.replaceAll("#/components/schemas/", "").replaceAll("#/definitions/", "");
}
} else {
type = ("request_" + method.toString() + "_" + path+ "_" + consume).replace("/", "_");
api.getDefinitions().put(type, model);
}
ApiBodyParameter bodyParam = new ApiBodyParameter(type);
bodyParam.setMediaType(consume);
if(apiRef!=null) {
bodyParam.setElement(apiRef);
}else {
bodyParam.setElement(type);
}
if(requestBody.getRequired() != null)
bodyParam.setRequired(requestBody.getRequired());
bodyParam.setDescription(requestBody.getDescription());
lst.add(bodyParam);
}
}
return lst;
}
private void addRequestParameter(Parameter paramP, ApiRequest request, HttpRequestMethod method, String path, OpenapiApi api) {
// resolve ref parameter
Parameter param = this.resolveParameterRef(paramP, api);
if(param==null) {
param = paramP;
}
AbstractApiParameter abstractParam = null;
String name = param.getName();
if(name==null && param.get$ref()!=null) {
// provo a risolvere il nome di un eventuale parametro riferito
name = getRefParameterName(param.get$ref(), api);
}
ApiParameterSchema apiParameterSchema = getParameterSchema(param.getSchema(), param.get$ref(), name,
null,
param.getStyle()!=null ? param.getStyle().toString(): null,
param.getExplode(),
api);
if(this.debug) {
System.out.println("=======================================");
System.out.println("REQUEST ("+method+" "+path+") name ["+name+"] required["+param.getRequired()+"] className["+param.getClass().getName()+"] ref["+param.get$ref()+"] apiParameterSchema["+apiParameterSchema.toString()+"]");
System.out.println("=======================================");
}
if(param instanceof PathParameter) {
abstractParam = new ApiRequestDynamicPathParameter(name, apiParameterSchema);
} else if(param instanceof QueryParameter) {
abstractParam = new ApiRequestQueryParameter(name, apiParameterSchema);
} else if(param instanceof HeaderParameter) {
abstractParam = new ApiHeaderParameter(name, apiParameterSchema);
} else if(param instanceof CookieParameter) {
abstractParam = new ApiCookieParameter(name, apiParameterSchema);
}
if(abstractParam == null) {
if(param.getIn() != null) {
if(param.getIn().equals("query")) {
abstractParam = new ApiRequestQueryParameter(name, apiParameterSchema);
} else if(param.getIn().equals("header")) {
abstractParam = new ApiHeaderParameter(name, apiParameterSchema);
} else if(param.getIn().equals("cookie")) {
abstractParam = new ApiCookieParameter(name, apiParameterSchema);
} else if(param.getIn().equals("path")) {
abstractParam = new ApiRequestDynamicPathParameter(name, apiParameterSchema);
}
}
}
if(abstractParam != null) {
abstractParam.setDescription(param.getDescription());
if(param.getRequired() != null)
abstractParam.setRequired(param.getRequired());
if(abstractParam instanceof ApiRequestDynamicPathParameter) {
request.addDynamicPathParameter((ApiRequestDynamicPathParameter) abstractParam);
} else if(abstractParam instanceof ApiRequestQueryParameter) {
request.addQueryParameter((ApiRequestQueryParameter) abstractParam);
} else if(abstractParam instanceof ApiHeaderParameter) {
request.addHeaderParameter((ApiHeaderParameter) abstractParam);
} else if(abstractParam instanceof ApiCookieParameter) {
request.addCookieParameter((ApiCookieParameter) abstractParam);
} else if(abstractParam instanceof ApiRequestFormParameter) {
request.addFormParameter((ApiRequestFormParameter) abstractParam);
}
}
}
private Parameter resolveParameterRef(Parameter p, OpenapiApi api) {
if(p.get$ref()==null || "".equals(p.get$ref())) {
return p;
}
String ref = p.get$ref();
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
boolean refParameters = ref.startsWith("#/components/parameters/");
if(!refParameters) {
return p;
}
if(api.getApi().getComponents().getParameters()==null || api.getApi().getComponents().getParameters().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+p.getName()+"' non corretto: parametri definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return null;
}
}
else {
String checkRef = ref.trim().replaceAll("#/components/parameters/", "");
Parameter param = null;
Iterator<String> itKeys = api.getApi().getComponents().getParameters().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
param = api.getApi().getComponents().getParameters().get(key);
break;
}
}
if(param==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+p.getName()+"' non corretto: ref '"+ref+"' non presente tra i parametri definiti come componenti");
}
}
return param;
}
}
private String getRefParameterName(String refParam, OpenapiApi api) {
if(refParam != null) {
String ref = refParam;
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
boolean refParameters = ref.startsWith("#/components/parameters/");
if(refParameters) {
if(api.getApi()==null) {
throw new RuntimeException("Parametro non corretto: api da cui risolvere la ref '"+ref+"' non trovata");
}
if(api.getApi().getComponents()==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro non corretto: componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return refParam;
}
}
else {
if(api.getApi().getComponents().getParameters()==null || api.getApi().getComponents().getParameters().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro non corretto: parametri definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return refParam;
}
}
else {
String checkRef = ref.trim().replaceAll("#/components/parameters/", "");
Parameter param = null;
Iterator<String> itKeys = api.getApi().getComponents().getParameters().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
param = api.getApi().getComponents().getParameters().get(key);
break;
}
}
if(param==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro non corretto: ref '"+ref+"' non presente tra i parametri definiti come componenti");
}
else {
return refParam;
}
}
else {
return param.getName();
}
}
}
}
}
return null;
}
/*
private String getParameterType(Schema<?> schema, String refParam, String name, OpenapiApi api) {
if(refParam != null) {
String ref = refParam;
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
boolean refHeaders = ref.startsWith("#/components/headers/");
boolean refParameters = ref.startsWith("#/components/parameters/");
boolean refSchema = ref.startsWith("#/components/schemas/");
if(refHeaders || refParameters || refSchema) {
if(api.getApi()==null) {
throw new RuntimeException("Parametro '"+name+"' non corretto: api da cui risolvere la ref '"+ref+"' non trovata");
}
else {
if(api.getApi().getComponents()==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return refParam;
}
}
else {
if(refHeaders) {
if(api.getApi().getComponents().getHeaders()==null || api.getApi().getComponents().getHeaders().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: headers definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return refParam;
}
}
String checkRef = ref.trim().replaceAll("#/components/headers/", "");
Header hdr = null;
Iterator<String> itKeys = api.getApi().getComponents().getHeaders().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
hdr = api.getApi().getComponents().getHeaders().get(key);
break;
}
}
if(hdr==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra gli headers definiti come componenti");
}
else {
return refParam;
}
}
else {
return getParameterType(hdr.getSchema(), hdr.get$ref(), name, api);
}
}
else if(refParameters) {
if(api.getApi().getComponents().getParameters()==null || api.getApi().getComponents().getParameters().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: parametri definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return refParam;
}
}
String checkRef = ref.trim().replaceAll("#/components/parameters/", "");
Parameter param = null;
Iterator<String> itKeys = api.getApi().getComponents().getParameters().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
param = api.getApi().getComponents().getParameters().get(key);
break;
}
}
if(param==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra i parametri definiti come componenti");
}
else {
return refParam;
}
}
else {
if(name==null && param.getName()!=null) {
name = param.getName();
}
return getParameterType(param.getSchema(), param.get$ref(), name, api);
}
}
else {
if(api.getApi().getComponents().getSchemas()==null || api.getApi().getComponents().getSchemas().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: schemi definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return refParam;
}
}
String checkRef = ref.trim().replaceAll("#/components/schemas/", "");
Schema<?> schemaRiferito = null;
Iterator<String> itKeys = api.getApi().getComponents().getSchemas().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
schemaRiferito = api.getApi().getComponents().getSchemas().get(key);
break;
}
}
if(schemaRiferito==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra gli schemi definiti come componenti");
}
else {
return refParam;
}
}
else {
return getParameterType(schemaRiferito, null, name, api);
}
}
}
}
}
else {
// i requestBodies e le response non dovrebbero rientrare in questo metodo
return ref.replaceAll("#/components/schemas/", "").replaceAll("#/definitions/", "");
}
}
if(schema==null) {
throw new RuntimeException("Parametro '"+name+"' non corretto: schema non definito");
}
if(schema.get$ref() != null) {
return getParameterType(schema, schema.get$ref(), name, api);
}
if(schema instanceof ArraySchema) {
return getParameterType(((ArraySchema)schema).getItems(), null, name, api);
}
if(schema instanceof ComposedSchema) {
ComposedSchema cs = (ComposedSchema) schema;
if(cs.getAnyOf()!=null && !cs.getAnyOf().isEmpty() && cs.getAnyOf().get(0)!=null) {
// utilizzo il primo schema
//NO NON VA BENE. DEVO STRUTTURARE L'INFORMAZIONE INSIEME ALLA RESTRIZIONE come una lista ???
if(cs.getAnyOf().get(0).getFormat() != null) {
return cs.getAnyOf().get(0).getFormat();
} else {
return cs.getAnyOf().get(0).getType();
}
// PRIMA TERMINARE COSI PER VEDERE SE FUNZIONA USANDO UN TIPO A CASO
}
else if(cs.getAllOf()!=null && !cs.getAllOf().isEmpty() && cs.getAllOf().get(0)!=null) {
// utilizzo il primo schema
//NO NON VA BENE. DEVO STRUTTURARE L'INFORMAZIONE INSIEME ALLA RESTRIZIONE come una lista ???
if(cs.getAllOf().get(0).getFormat() != null) {
return cs.getAllOf().get(0).getFormat();
} else {
return cs.getAllOf().get(0).getType();
}
// ALL OFF HA SENSO ??????????????? PROVARE COME SI COMPORTA OPENAPI
}
}
if(schema.getFormat() != null) {
return schema.getFormat();
} else {
return schema.getType();
}
}
private ApiSchemaTypeRestriction getParameterSchemaTypeRestriction(Schema<?> schema, String ref, String name,
Boolean arrayParameter, String style, Boolean explode, OpenapiApi api) {
if(ref != null) {
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
boolean refHeaders = ref.startsWith("#/components/headers/");
boolean refParameters = ref.startsWith("#/components/parameters/");
boolean refSchema = ref.startsWith("#/components/schemas/");
if(refHeaders || refParameters || refSchema) {
if(api.getApi()==null) {
throw new RuntimeException("Parametro '"+name+"' non corretto: api da cui risolvere la ref '"+ref+"' non trovata");
}
else {
if(api.getApi().getComponents()==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return null;
}
}
else {
if(refHeaders) {
if(api.getApi().getComponents().getHeaders()==null || api.getApi().getComponents().getHeaders().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: headers definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return null;
}
}
String checkRef = ref.trim().replaceAll("#/components/headers/", "");
Header hdr = null;
Iterator<String> itKeys = api.getApi().getComponents().getHeaders().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
hdr = api.getApi().getComponents().getHeaders().get(key);
break;
}
}
if(hdr==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra gli headers definiti come componenti");
}
else {
return null;
}
}
else {
return getParameterSchemaTypeRestriction(hdr.getSchema(), hdr.get$ref(), name,
arrayParameter,
hdr.getStyle()!=null ? hdr.getStyle().toString(): null,
hdr.getExplode(),
api);
}
}
else if(refParameters) {
if(api.getApi().getComponents().getParameters()==null || api.getApi().getComponents().getParameters().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: parametri definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return null;
}
}
String checkRef = ref.trim().replaceAll("#/components/parameters/", "");
Parameter param = null;
Iterator<String> itKeys = api.getApi().getComponents().getParameters().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
param = api.getApi().getComponents().getParameters().get(key);
break;
}
}
if(param==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra i parametri definiti come componenti");
}
else {
return null;
}
}
else {
if(name==null && param.getName()!=null) {
name = param.getName();
}
return getParameterSchemaTypeRestriction(param.getSchema(), param.get$ref(), name,
arrayParameter,
param.getStyle()!=null ? param.getStyle().toString(): null,
param.getExplode(),
api);
}
}
else {
if(api.getApi().getComponents().getSchemas()==null || api.getApi().getComponents().getSchemas().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: schemi definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
return null;
}
}
String checkRef = ref.trim().replaceAll("#/components/schemas/", "");
Schema<?> schemaRiferito = null;
Iterator<String> itKeys = api.getApi().getComponents().getSchemas().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
schemaRiferito = api.getApi().getComponents().getSchemas().get(key);
break;
}
}
if(schemaRiferito==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra gli schemi definiti come componenti");
}
else {
return null;
}
}
else {
return getParameterSchemaTypeRestriction(schemaRiferito, null, name,
arrayParameter,
style,
explode,
api);
}
}
}
}
}
else {
return null; // schema non trovato.
}
}
if(schema.get$ref() != null) {
return getParameterSchemaTypeRestriction(schema, schema.get$ref(), name,
arrayParameter,
style,
explode,
api);
}
if(schema instanceof ArraySchema) {
return getParameterSchemaTypeRestriction(((ArraySchema)schema).getItems(), null, name,
true,
style,
explode,
api);
}
return this.convertTo(schema, arrayParameter, style, explode);
}
*/
private ApiParameterSchema getParameterSchema(Schema<?> schema, String ref, String name,
Boolean arrayParameter, String style, Boolean explode, OpenapiApi api) {
if(ref != null) {
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
boolean refHeaders = ref.startsWith("#/components/headers/");
boolean refParameters = ref.startsWith("#/components/parameters/");
boolean refSchema = ref.startsWith("#/components/schemas/");
if(refHeaders || refParameters || refSchema) {
if(api.getApi()==null) {
throw new RuntimeException("Parametro '"+name+"' non corretto: api da cui risolvere la ref '"+ref+"' non trovata");
}
else {
if(api.getApi().getComponents()==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
else {
if(refHeaders) {
if(api.getApi().getComponents().getHeaders()==null || api.getApi().getComponents().getHeaders().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: headers definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
String checkRef = ref.trim().replaceAll("#/components/headers/", "");
Header hdr = null;
Iterator<String> itKeys = api.getApi().getComponents().getHeaders().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
hdr = api.getApi().getComponents().getHeaders().get(key);
break;
}
}
if(hdr==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra gli headers definiti come componenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
else {
return getParameterSchema(hdr.getSchema(), hdr.get$ref(), name,
arrayParameter,
hdr.getStyle()!=null ? hdr.getStyle().toString(): null,
hdr.getExplode(),
api);
}
}
else if(refParameters) {
if(api.getApi().getComponents().getParameters()==null || api.getApi().getComponents().getParameters().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: parametri definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
String checkRef = ref.trim().replaceAll("#/components/parameters/", "");
Parameter param = null;
Iterator<String> itKeys = api.getApi().getComponents().getParameters().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
param = api.getApi().getComponents().getParameters().get(key);
break;
}
}
if(param==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra i parametri definiti come componenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
else {
if(name==null && param.getName()!=null) {
name = param.getName();
}
return getParameterSchema(param.getSchema(), param.get$ref(), name,
arrayParameter,
param.getStyle()!=null ? param.getStyle().toString(): null,
param.getExplode(),
api);
}
}
else {
if(api.getApi().getComponents().getSchemas()==null || api.getApi().getComponents().getSchemas().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: schemi definiti come componenti, sui cui risolvere la ref '"+ref+"', non presenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
String checkRef = ref.trim().replaceAll("#/components/schemas/", "");
Schema<?> schemaRiferito = null;
Iterator<String> itKeys = api.getApi().getComponents().getSchemas().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(checkRef)) {
schemaRiferito = api.getApi().getComponents().getSchemas().get(key);
break;
}
}
if(schemaRiferito==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Parametro '"+name+"' non corretto: ref '"+ref+"' non presente tra gli schemi definiti come componenti");
}
else {
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(ref, null);
return aps;
}
}
else {
return getParameterSchema(schemaRiferito, null, name,
arrayParameter,
style,
explode,
api);
}
}
}
}
}
else {
// i requestBodies e le response non dovrebbero rientrare in questo metodo
String _type = ref.replaceAll("#/components/schemas/", "").replaceAll("#/definitions/", "");
ApiSchemaTypeRestriction _schema = null; // schema non trovato.
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(_type, _schema);
return aps;
}
}
if(schema==null) {
throw new RuntimeException("Parametro '"+name+"' non corretto: schema non definito");
}
if(schema.get$ref() != null) {
return getParameterSchema(schema, schema.get$ref(), name,
arrayParameter,
style,
explode,
api);
}
if(schema instanceof ArraySchema) {
return getParameterSchema(((ArraySchema)schema).getItems(), null, name,
true,
style,
explode,
api);
}
if(schema instanceof ComposedSchema) {
ComposedSchema cs = (ComposedSchema) schema;
if(cs.getAnyOf()!=null && !cs.getAnyOf().isEmpty()) {
ApiParameterSchema aps = new ApiParameterSchema();
aps.setComplexType(ApiParameterSchemaComplexType.anyOf);
for (Schema<?> apiSchemaAnyOf : cs.getAnyOf()) {
String _type = null;
if(apiSchemaAnyOf.getFormat() != null) {
_type = apiSchemaAnyOf.getFormat();
} else {
_type = apiSchemaAnyOf.getType();
}
ApiSchemaTypeRestriction _schema = this.convertTo(apiSchemaAnyOf, arrayParameter, style, explode);
aps.addType(_type, _schema);
}
return aps;
}
else if(cs.getAllOf()!=null && !cs.getAllOf().isEmpty()) {
ApiParameterSchema aps = new ApiParameterSchema();
aps.setComplexType(ApiParameterSchemaComplexType.allOf);
for (Schema<?> apiSchemaAllOf : cs.getAllOf()) {
String _type = null;
if(apiSchemaAllOf.getFormat() != null) {
_type = apiSchemaAllOf.getFormat();
} else {
_type = apiSchemaAllOf.getType();
}
ApiSchemaTypeRestriction _schema = this.convertTo(apiSchemaAllOf, arrayParameter, style, explode);
aps.addType(_type, _schema);
}
return aps;
}
else if(cs.getOneOf()!=null && !cs.getOneOf().isEmpty()) {
ApiParameterSchema aps = new ApiParameterSchema();
aps.setComplexType(ApiParameterSchemaComplexType.oneOf);
for (Schema<?> apiSchemaOneOf : cs.getOneOf()) {
String _type = null;
if(apiSchemaOneOf.getFormat() != null) {
_type = apiSchemaOneOf.getFormat();
} else {
_type = apiSchemaOneOf.getType();
}
ApiSchemaTypeRestriction _schema = this.convertTo(apiSchemaOneOf, arrayParameter, style, explode);
aps.addType(_type, _schema);
}
return aps;
}
}
String _type = null;
if(schema.getFormat() != null) {
_type = schema.getFormat();
} else {
_type = schema.getType();
}
if(_type==null && schema.getTypes()!=null && !schema.getTypes().isEmpty()) {
_type=schema.getTypes().iterator().next();
}
ApiSchemaTypeRestriction _schema = this.convertTo(schema, arrayParameter, style, explode);
ApiParameterSchema aps = new ApiParameterSchema();
aps.addType(_type, _schema);
return aps;
}
private ApiSchemaTypeRestriction convertTo(Schema<?> schema, Boolean arrayParameter, String style, Boolean explode) {
ApiSchemaTypeRestriction schemaTypeRestriction = new ApiSchemaTypeRestriction();
schemaTypeRestriction.setSchema(schema);
schemaTypeRestriction.setType(schema.getType());
schemaTypeRestriction.setFormat(schema.getFormat());
schemaTypeRestriction.setMinimum(schema.getMinimum());
schemaTypeRestriction.setExclusiveMinimum(schema.getExclusiveMinimum());
schemaTypeRestriction.setMaximum(schema.getMaximum());
schemaTypeRestriction.setExclusiveMaximum(schema.getExclusiveMaximum());
schemaTypeRestriction.setMultipleOf(schema.getMultipleOf());
schemaTypeRestriction.setMinLength(schema.getMinLength()!=null ? Long.valueOf(schema.getMinLength()) : null);
schemaTypeRestriction.setMaxLength(schema.getMaxLength()!=null ? Long.valueOf(schema.getMaxLength()) : null);
schemaTypeRestriction.setPattern(schema.getPattern());
schemaTypeRestriction.setEnumValues(schema.getEnum());
schemaTypeRestriction.setArrayParameter(arrayParameter);
schemaTypeRestriction.setStyle(style);
if(explode!=null) {
schemaTypeRestriction.setExplode(explode.booleanValue()+"");
}
return schemaTypeRestriction;
}
private ApiResponse createResponses(String responseK, io.swagger.v3.oas.models.responses.ApiResponse response, HttpRequestMethod method, String path, OpenapiApi api) {
ApiResponse apiResponse= new ApiResponse();
int status = -1;
try{
if("default".equals(responseK)) {
apiResponse.setDefaultHttpReturnCode();
}
else {
status = Integer.parseInt(responseK);
apiResponse.setHttpReturnCode(status);
}
} catch(NumberFormatException e) {
throw new RuntimeException("Stato non supportato ["+responseK+"]", e);
}
// if(status<=0) {
// status = 200;
// }
if(response.get$ref()!=null) {
String ref = response.get$ref();
boolean external = false;
if(ref.contains("#")) {
external = !ref.trim().startsWith("#");
ref = ref.substring(ref.indexOf("#"));
}
ref = ref.trim().replaceAll("#/components/responses/", "").replaceAll("#/definitions/", "");
if(api.getApi()==null) {
throw new RuntimeException("Stato non corretto ["+responseK+"]: api da cui risolvere la ref '"+response.get$ref()+"' non trovata");
}
if(api.getApi().getComponents()==null) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Stato non corretto ["+responseK+"]: componenti, sui cui risolvere la ref '"+response.get$ref()+"', non presenti");
}
}
else {
if(api.getApi().getComponents().getResponses()==null || api.getApi().getComponents().getResponses().size()<=0) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Stato non corretto ["+responseK+"]: risposte definite come componenti, sui cui risolvere la ref '"+response.get$ref()+"', non presenti");
}
}
else {
boolean find = false;
Iterator<String> itKeys = api.getApi().getComponents().getResponses().keySet().iterator();
while (itKeys.hasNext()) {
String key = (String) itKeys.next();
if(key.equals(ref)) {
response = api.getApi().getComponents().getResponses().get(key);
find = true;
break;
}
}
if(!find) {
if(!external || this.resolveExternalRef) {
throw new RuntimeException("Stato non corretto ["+responseK+"]: ref '"+response.get$ref()+"' non presente tra le risposte definite come componenti");
}
}
}
}
}
apiResponse.setDescription(response.getDescription());
if(response.getHeaders() != null) {
for(String header: response.getHeaders().keySet()) {
Header property = response.getHeaders().get(header);
ApiParameterSchema apiParameterSchema = getParameterSchema(property.getSchema(), property.get$ref(), header,
null,
property.getStyle()!=null ? property.getStyle().toString(): null,
property.getExplode(),
api);
if(this.debug) {
System.out.println("=======================================");
System.out.println("RESPONSE ("+method+" "+path+") name ["+header+"] required["+property.getRequired()+"] className["+property.getClass().getName()+"] ref["+property.get$ref()+"] apiParameterSchema["+apiParameterSchema+"]");
System.out.println("=======================================");
}
ApiHeaderParameter parameter = new ApiHeaderParameter(header, apiParameterSchema);
parameter.setDescription(property.getDescription());
if(property.getRequired() != null)
parameter.setRequired(property.getRequired());
apiResponse.addHeaderParameter(parameter);
}
}
if(response.getContent() != null && !response.getContent().isEmpty()) {
for(String contentType: response.getContent().keySet()) {
MediaType mediaType = response.getContent().get(contentType);
Schema<?> schema = mediaType.getSchema();
String name = ("response_" +method.toString() + "_" + path + "_" + responseK + "_" + contentType).replace("/", "_");
String type = null;
ApiReference apiRef = null;
if(schema!=null && schema.get$ref()!= null) {
String href = schema.get$ref().trim();
if(href.contains("#") && !href.startsWith("#")) {
type = href.substring(href.indexOf("#"), href.length());
type = type.replaceAll("#/components/schemas/", "").replaceAll("#/definitions/", "");
String ref = href.split("#")[0];
File fRef = new File(ref);
apiRef = new ApiReference(fRef.getName(), type);
}
else {
type = href.replaceAll("#/components/schemas/", "").replaceAll("#/definitions/", "");
}
} else {
type = ("response_" +method.toString() + "_" + path + "_" + responseK + "_" + contentType).replace("/", "_");
api.getDefinitions().put(type, schema);
}
ApiBodyParameter bodyParam = new ApiBodyParameter(name);
bodyParam.setMediaType(contentType);
if(apiRef!=null) {
bodyParam.setElement(apiRef);
}else {
bodyParam.setElement(type);
}
// String typeF = getParameterType(schema, null);
// bodyParam.setElement(type);
bodyParam.setRequired(true);
apiResponse.addBodyParameter(bodyParam);
}
}
return apiResponse;
}
}